マニュアル: Kotlin

投稿日: 更新日:

文法

class

Classes and Inheritance - Kotlin Programming Language

コンストラクタの定義

プライマリコンストラクタという概念があって、ヘッダに書く。 privateの場合はprivate constructorと書く。

class Person constructor(firstName: String) {
}

constructorはアノテーションとかvisibility modifiers(privateとか)が ない場合は省略可能。

class Person(firstName: String) {
}

コンストラクタの実装

コンストラクタの実装は、initキーワードつきのブロック(イニシャライザ)を使う。 (RubyのinitializeとかObjective-Cのinitとかと同じですね)

init {
}

イニシャライザは複数定義可能で、 複数定義した場合、上から処理される。

セカンダリコンストラクタ

セカンダリコンストラクタはプライマリコンストラクタを呼ぶ必要がある。 this(name)がその呼び出し。

class Person(val name: String) {
  constructor(name: String, parent: Person) : this(name) {
    parent.children.add(this);
  }
}

インスタンス化

https://kotlinlang.org/docs/reference/classes.html#creating-instances-of-classes

メソッド呼び出しのようにする。 (newキーワードは存在しない)

var customer = Customer("Joe Smith")

継承

デフォルトはAnyを継承。Objectではない。 Anyequals(), hashCode(), toString()以外は持たない。 つまり、以下のメソッドがない。

  • clone()
  • finalize()
  • getClass()
  • notify() / wait()系

継承をするときには、:で区切って右側にスーパークラスを書く。 継承可能なクラスにはopenを付ける。 Javaとは逆。素晴らしい。

メソッドのオーバーライド

WIP

データクラス

C言語における構造体、あるいはDDDにおけるValue Objectなどを扱うために便利そう。 解説では[DTO](Data Transfer Object)のためと書かれています。

自動で以下のものが定義される。

  • getter
  • (varで定義した場合)setter
  • equals
  • hashCode
  • toString
  • copy 何?
  • component1(), component2(), 何?

シールクラス

https://kotlinlang.org/docs/reference/sealed-classes.html

  • 継承を制限する。具体的には、同じ[クラス]に定義されたクラス以外では継承できない。

個人的な経験だと、最初はクラスで十分だと思っていたが、 後でインタフェースに変えたときに泣く泣く継承を使って実現したケースがあるので(クラスとインタフェースは互換性がない)、そういうときに使えるかもしれない。

コメント

Javaと違ってブロックコメントのネストが可能。

文字列

以下の2つがある。

  • エスケープ済み文字列(escaped string)
    • 通常のJava文字列とほぼ同じ。ただし、$はテンプレートとして展開されてるため、\$のようにする。
  • 生文字列(raw string)
    • ダブルクォーテーション3つ(""")で挟む。
    • エスケープできない。$自体を書くときは${'$'}のように書く。
    • 前の空白を削除したいときはtrimMarginを使う。

文字列テンプレート

$iまたは${i}形式で書ける(bashとかと同じ)。 生文字列中に$自体を書くときは${'$'}のように書く。 (生文字列はエスケープできない)。

Unit

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html

Javaにおけるvoidと同じ。

var / val

  • var: 書き換え可能(mutable)
  • val: 書き換え不可能(immutable)

if

https://kotlinlang.org/docs/reference/control-flow.html#if-expression

Javaとの違い

  • if文が値を返す(Rubyと同じ)
  • ブロックの最後の値を返す(Rubyと同じ)

for

https://kotlinlang.org/docs/reference/control-flow.html#for-loops

  • for (item in items) JavaScriptライク?
    • indices: インデックス
    • withIndex(): インデックス付きループ(Rubyで便利なやつ)

when

https://kotlinlang.org/docs/reference/control-flow.html#when-expression

switchと意味合い的には同じ。ただ柔軟性がある。

  • 0, 1 => ...のようにカンマ区切りで複数指定ができる
  • 任意の式の結果が使える
    • 例が分かりにくいが、以下のように xparseInt(s) と同じかどうかで分岐できる。
import java.lang.Integer.parseInt
 
fun foo(s: String, x: Int) {
  when (x) {
    parseInt(s) -> print("s encodes x")
    else -> print("s does not encode x")
  }
}
 
fun main(args: Array<String>) {
  foo("1", 1) // -> s encodes x
  foo("2", 3) // -> s does not encode x
}
  • 範囲(range)による指定ができる
    • 例: in 1..10
      • !で否定も可能
      • 例: !in 1..10
  • is(スマートキャスト)
  • 普通のif-else if の代わりにもなる。

null関連

!!オペレータ

強制的にアンラップして非nullとして扱う。 当然nullが入っている場合はNullPointerExceptionになる。 ちなみにSwiftは!

Safe Cast

https://kotlinlang.org/docs/reference/null-safety.html#safe-casts

asを使うことで、キャストに失敗したときはnullを返すようにできる。

スマートキャスト

https://kotlinlang.org/docs/reference/typecasts.html#smart-casts

instanceofとキャストを同時に行う機能。

fun demo(x: Any) {
  if (x is String) {
    print(x.length)
  }
}

Javaで書くとこんな感じ(のはず)。

void demo(Object x) {
  if (x instanceof String) {
    System.out.print(((String)x).length());
  }
}

ブロックの中でなくても、キャストして問題ないと判断できる場所では使用可能。 例は以下の通り(インデントがずれてる?)

if (x !is String) return
  print(x.length)

逆引きマニュアル