Fablog

社会人マイナス1年生のブログ / プログラミング / 料理 / ビットコイン

Kotlinについて学んだ [Kotlin助走読本の要約]

概要

  • kotlinを書くことになった
  • kotlinユーザーグループという団体がKotlin助走読本を無料で配布している
  • 先輩に進められたので読んだ
  • 読むだけだと頭に入らないので簡単に要約した
  • 本体も86pと大分要約された本なので是非読んでみることをおすすめすする
  • 勉強になりました、kotlinユーザーグループの方々ありがとうございます

1章 Kotlinについて知る

1.1 Kotlinとは

  • KotlinはJetBrain社がJavaに代わり、より簡潔に書くことを目的として作られた静的型付き言語
  • JavaだけでなくJavascriptへのトランスパイルも可能
  • Javaと相互運用するように設計されているのでJavaプロジェクトの一部でKotlinを使うことも出来る
  • Androidで公式サポートされている

Kotlinを使うと何が嬉しいのか

  • Androidとの親和性が高い

    • Kotlin <-> Java でお互いのコードを呼び出すことができる
    • ランタイムメソッド数が少ないので64Kメソッド問題を回避しやすい
    • ライブラリサイズが少ない
    • JetBrainによる強力なIDEサポートが有る
  • 生産性が高い

    • data クラスのような様々な文法を使うことによって記述量を少なく出来る
    • コレクション操作などの便利な関数が用意されている
    • 拡張関数や遅延初期化や演算子オーバーロードなど様々な便利文法が用意されている
  • メンタビリティが高い

1.3 Kotlinの特徴

  • 静的型付け言語

  • 対象のプラットフォーム

    • フルスタックな言語を目指し開発が行われている
    • JVM上で使用可能なため、Androidを始めとしてサーバーでも動作する
  • 高階関数

    • 関数オブジェクトを引数にしたり戻り値にしたりできる
fun <T> lock(lock: Lock, body: () -> T): T {
    lock.lock()
    try {
        // 引数で渡された関数オブジェクトを実行している
        return body()
    }
    finally {
        lock.unlock()
    }
}
  • ラムダ式
    • 関数を宣言せずに関数オブジェクトを生成できる
max(strings, { a, b -> a.length < b.length })

1.4 将来の展望

  • JetBrain社としての展望

    • Andoid, iOS, サーバーサイド, Webフロントエンド, ネイティブなど各種プラットフォーム開発を目指している
  • AndroidとKotlin

    • 2017年にAndroid公式開発言語としてサポートされた
    • 今後も様々なサポートやツールが増えることが予想される

1.5 導入事例

  • Expedia
  • Pintarest
  • Retty
  • Pairs

第2章 Kotlinを学ぶ

環境構築からHelloWorldまで

  • 環境構築

    • Web上の実行環境で試してみる

      • try.kotlinlang.org
      • Program arguments の欄に何かしらの文字列を指定する
      • Runボタンを押す
    • AndroidStudio上でKotlin環境を作る

  • javaの場合はエントリーポイントとなるmainメソッドを定義するためにはclassを定義してそのstaticメソッドとして定義する必要があったが、Kotlinはトップレベルに関数を定義できる

  • 関数定義はfunで始まる
  • 引数の型は後ろに置く
  • セミコロンが不要
  • Javaでいるvoid型のメソッドはUnit型と定義され、戻り値の記述を省略できる
fun main(args: Array<String>) {
    println("Hello, ${args[0]}!")
}
  • 文字列中に$とともに変数や式を挿入するとそれを評価した値を文字列として連結してくれる
val i = 42 // 変数 i に 42 を代入
val s = "すべての答え:$i" // -> すべての答え:42
val s1 = "1 + 1 は${ 1 + 1 }です。" // 1 + 1 は 2 です。
val s2 = "s1 の⻑さは${s1.length}です。" // s1 の⻑さは 10 です。
  • classの定義

    • クラス名の後に:を次ぐけて継承元のクラスを記述する
    • 何も指定しない場合はpublicスコープなクラスとなる
  • クラスのメソッド

    • オーバーライドメソッドはfunの前にoverrideという修飾子をつける
  • null許容型

    • 型の後ろに?があるものはNull許容型であることを示している

2.2 Kotlinの味見

基本文法

  • 変数宣言
    • varで宣言すると再代入が可能
    • valで宣言すると再代入ができない
val num : Int = 1
num = 2 // =>コンパイルエラー
var num2 : Int = 2
num2 = 3 // =>コンパイルエラーにならない
  • 型推論
    • 型を省略できるのは便利ではありますが、開発者同士で分かりにくい場合は明示的に宣言する方がよい
val num = 1
  • if文は式としても扱うことが出来る
val result : String = if(true) {"true"} else { "false" }
println(result) // =>true

// else 節のない場合は、値を返さない Java と同じような if 文として扱われる
  • siwtch文の代わりにwhen式を使う
    • 条件のうち、必ずどれか 1 つに一致する必要がある
    • 左側を条件式にすることも可能
val value = 1
when {
    value == 1-> println("one")
    value == 2-> println("two")
    else -> println("other")
}
  • for文

    • mapOf: マップを生成する関数
    • listOf: リストを生成する関数
    • setOf: セットを生成する関数
    • for(i in 0..4)のようなRangeを使った書き方
    • for(i in 4 downTo 0)のような逆順ループ
  • white, do-whileもJava同様に使える

Null安全

  • kotlinにおける通常の型はnullの代入を許容しない
  • nullを許容するには型の後ろに?をつける

  • nullチェックと安全な呼び出し

    • Null 許容型のメソッドを呼び出すためには、事前に if を用いて null でないことをチェックしなければならない
    • ?演算子を使えば、Null 許容型のメソッドやプロパティを参照することができる
    • エルビル演算子: null チェックは?:演算子を用いて記述することができる
    • !!演算子を用いるとNull許容型をNull非許容型に無理やり変換できる
val l : Int? = b?.length

var b: String? = "abc"
val l : Int = if(b != null) b.length else -1
val l : Int = b?.length ?: -1

val l : Int = b!!.length

関数

  • 関数はfunを使って定義する
  • 関数名: 型というフォーマットで引数を宣言する
  • 引数はコンマで分ける
  • 戻り値がUnit型以外のときは戻り値も定義しなければならない
    • 関数が1つの式で構成される場合は=を書いてブロックを省略できる
    • さらに、コンパイラーが型推論をできるような戻り値の型であれば、戻り値の型の定義を省略することも可能です。
  • 引数のデフォルト値は型定義のあとに=を書いて定義する
  • 名前付き引数も使える
    • 名前付き引数を使った場合、後に続く引数は全て名前付きにしなくてはならない
  • 関数名の前に<>を使うことで型パラメーターを使うことも出来る
fun add(x: Int, y: Int): Int {
    return x + y
}

fun add(x: Int, y: Int): Int = x + y
fun add(x: Int, y: Int) = x + y

fun <T> singletonList(item: T): List<T>{}
  • 高位関数
    • 関数の引数や戻り値に関数オブジェクトを使う関数
    • 具体的な処理を関数の外に出すことによって凡庸化できるようにする
fun <T> lock(lock: Lock, body: () -> T): T {
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}
  • ラムダ式
    • 関数を宣言せずに関数オブジェクト生成できる
    • 引数の最後にラムダ式を渡している場合は引数の外に記述することも可能
max(strings, { a, b -> a.length < b.length })
max(strings) { a, b -> a.length < b.length }
  • インライン関数
    • 実行時に関数オブジェクトを生成するとメモリコストが高くなる場合がある
    • funの前にinlineをつけることに よってコンパイル時にインライン展開されるようになる
inline fun lock<T>(lock: Lock, body: () -> T): T {
    // ...
}

クラス

  • class クラス名 {} で定義できる
  • クラスにメンバやメソッドが無い場合は波括弧を省略できる
  • val myClass = MyClass()のようにnew無しでインスタンス生成できる
  • コンストラクタ
    • コンストラクタはこのように定義する
      • class Person(name: String)
      • この記法をプライマリーコンストラクタと言う
      • プライマリーコンストラクタには処理が記述出来ない
    • アノテーションを書く場合はconstructerの記述が必要になる
      • class Person public @Inject constructor(name: String)
    • インスタンス生成時に行いたい処理はinitキーで定義する
    • コンストラクタを複数生成する場合はconstructerキーを使用する
class Person(val name: String) {
    init {
        logger.info("name = ${name}")
    }
    constructor(name: String, parent: Person) : this(name) {
    // 処理
    }
}
  • メソッドはクラス内に関数を定義すればいい
  • Kotlinでフィールドを定義するとバッキングフィールドというものが生成され、実際の値は底に格納される
    • 要するにプロパティを定義するだけで getter, setter が自動生成される
    • 自分でgetter/setterを定義することもでき、これを定義した場合はバッキングフィールドは定義されない
  • DIなどを利用していてインスタンス生成時に値を設定することが出来ない場合はlateinitキーを使うことで初期化を遅らせることが出来る
  • classの代わりにobjectキーをつかうことによってインスタンスが必ず1つしか生成されないシングルトンなクラスを定義できる
  • KotlinではJavaのようなstaticなメンバを定義することができない
  • インスタンスを生成しなくても利用できるメンバを定義したい場合は companion object キーを使う
  • open修飾子が付いているクラスについては:で継承することができる
  • 継承元のメソッドを上書きするときは、継承するメソッドと同じ名前のメソッドを定義し、override修飾子をつける
  • Javaと同様にファイルの戦闘でpackageキーを使うことでクラスなどの要素を名前空間で区切ることが出来る *アクセス制限
    • public: デフォルトの設定で公開範囲に制限はない
    • internal: 同一モジュール内に限り全公開
    • private: 同一ファイル内のみアクセス可能

データクラス

  • data クラスを定義すると次のメソッド自動で生成する
    • equals()
    • hasCode()
    • toString()
    • vomponentN()
      • 1から始まるメンバー変数の順番
    • copy()
  • data クラスの制限
    • コンストラクターは少なくとも1つの引数を保つ必要がある
    • コンストラクターの全ての引数はvalかvarで定義する必要がある
    • abstract open, sealed, inner 修飾子を付けられない
    • 継承できるのはsealedクラスのみ
  • インスタンスを分解して幾つかの変数に代入する分解宣言ができる

インターフェイス

拡張

  • 拡張関数
    • 任意の方に対して外部から関数を追加できる機能
    • 関数を追加したい方を関数名の手前に付け加えると定義できる
  • 拡張プロパティ
    • 拡張関数とおなじように任意のプロパティを外付けできる
  • 同一ファイル外から呼ぶ場合はimportが必要になる
  • 四則演算のようなモノを新しい方にも適用できるよにする演算子オーバーロードという仕組みがある
  • plusというメソッドが定義されていれば+という二項演算子をつかった計算を行うことができる

イコール

  • 同じ参照であるかを調べるときも同じオブジェクトの中身であるかを調べるときも == 演算子を使う

エイリアス

  • typealiasキーを使うことで既存の型に別名をあたえることができる

### 2.3 JavaからKotlinへの移行 * javaとkotlinは相互互換がある * KotlinとJavaを混在させる * メンテナンスコストがあがる * 境界を設けたほうが良い * kotlinからjavaを使うときの注意点 * javaでは予約語ではないがkotlinでは予約度なキーワードをバックフォーとでエスケープする * javaにはnull許容型がないため、呼び出し時に判断を求められる * 検査例外を無視するので意識してtry-catchなどを書くことが必要となる * javaからkotlinを使う * getter, setterが定義されているのでメンバ変数にはそれを用いてアクセスする * ラムダ式はSAM インターフェースに変換される * 拡張関数は対象のクラスを第一引数に取る関数が宣言されているという扱いになる * kotlin上でデフォルト引数を持っている場合でも全ての引数を渡す必要がある * デフォルト引数のある関数をオーバーロードするには@JvmOverloadsアノテーションを使う

3章 次のステップ

3.1 学習方法

  • 公式ページ
  • KotlinWeekly
  • について学びたい方におすすめなのは、書籍「Kotlin スタートブックー新しい Android プログラミングー(2016)⻑澤太郎著 リックテレコム
  • Kotlin Koans online
  • Google I/O 2017 : Introduction to Kotlin(和訳/要約)

3.2 コミュニティ

  • 日本Kotlinユーザーグループ
  • kotlin slack
  • kotlin conf

3.3 次回リリースの予告

  • 今回のリリースが最初で最後というわけではない
  • 少なくとも継続して新バージョンをリリースすることを検討している