KotlinLearning: 04-3 第一級オブジェクト

第一級オブジェクト

「(Kotlinの)関数は第一級オブジェクトである」
よく出て来る表現ですが、どういう意味なのか説明がないこともしばしばです。

Wikipedia – 第一級オブジェクト

Wikipediaによるとオブジェクト指向のオブジェクトとは特に関係はなく、ざっくりと次のような特徴を持つ対象のことのようです。

  • 無名のリテラルとして表現可能である。
  • 変数に格納可能である。
  • 関数のパラメータとして渡すことができる。
  • 関数の戻り値として返すことができる。
    …他

つまりは整数や浮動小数点などと同じように使うことが出来る、ということでしょう。

Javaでは関数はどこかで定義し、どこかから呼び出して使用するものでした。
Kotlinでは関数は第一級オブジェクトなので、他の数値や文字、文字列などと同じように扱うことができます。
確かに関数型に関数を格納したり、高階関数で引数や戻り値に関数を指定したり、できますね。

以下の様に関数を::で参照し、関数リテラルとして扱うこともできます。

fun printValue() {
	val value = 1
	println("value = $value")
}

fun main() { 
    val method = ::printValue //関数printValueを関数リテラルとして取得
    println(method.name) //関数名を表示

    method() //関数リテラルを実行
    method.invoke() //invoke関数で関数リテラルを実行
}

変数に入れた関数リテラルは任意のタイミングで実行することが出来ます。
実行する際は変数名に()を付けるか、invoke()メソッドを呼び出します。

型推論を使わずに関数型の変数を使用することも出来ます。
以下の例では(Int) -> Unit型(Intを引数に取り、戻り値を返さない関数型)になっています。
関数型を明示した場合nameプロパティは取得できないようです。

fun printValue(value: Int) {
	println("value = $value")
}

fun main() {    
    val method : (Int) -> Unit = ::printValue
    //println(method.name)
    method(1)
}

関数リテラルを変数に代入するのであれば、そもそも関数の定義時に名前を付ける必要などありません。
匿名関数(無名関数)にして直接変数に代入してしまいましょう。

fun main() {    
    val method = fun (value: Int) : String { return "value = $value" }
    println(method(1))
}

{}を外して式本体として定義しても問題ありません。

fun main() {    
    val method = fun (value: Int) = "value = $value"
    println(method(1))
}

同様の処理をラムダを用いて書くことが出来ます。

fun main() {    
    val method = { value:Int -> "value = $value" }
    println(method(1))
}

単に関数を変数に代入し任意のタイミングで実行するだけであれば、直接関数を呼び出してしまってもよいと思うでしょう。
確かにこれだけの用途ではその通りでしょう。

しかし第一級オブジェクトの特徴として「引数や戻り値に使える」という点を考慮するともう少し可能性が広がります。

Advertisements

Kotlin

Posted by codive