Slide 1

Slide 1 text

Kotlinの関数参照 2017-04-04 Kotlin勉強会@Sansan 長澤 太郎

Slide 2

Slide 2 text

自己紹介 ● たろう @ngsw_taro ● エムスリー株式会社のAndroidエンジニア ● Kotlinエバンジェリスト(自称) ● 著書「Kotlinスタートブック」

Slide 3

Slide 3 text

もくじ 1. 関数参照 2. レシーバが未定のメソッド参照 3. レシーバが確定のメソッド参照 4. プロパティも関数

Slide 4

Slide 4 text

1. 関数参照

Slide 5

Slide 5 text

関数オブジェクト ● Kotlinでは定義済みの関数のオブジェクトを得ること ができる ● 関数オブジェクトを変数に代入したり、別の関数の引 数に渡したり、持ち回して便利に使える。 ● 必ずしもオブジェクトではない(ヒント: インライン関 数)

Slide 6

Slide 6 text

コード例 // 普通の関数 fun succ(n: Int): Int = n + 1 // 関数オブジェクトを取得し、変数に代入 val myFunc: (Int)->Int = ::succ // ^^^^^^^^^^ 関数型 // メソッド呼び出しによる元の関数の計算を実行 myFunc.invoke(5) //=> 6 // 演算子オーバロードによる関数らしい記述 myFunc(7) //=> 8

Slide 7

Slide 7 text

応用例 // 高階関数の引数に「関数参照」を渡す listOf(1, 2, 3).map(::succ) //=> [2, 3, 4] // ラムダ式を使えば同じ listOf(1, 2, 3).map { succ(it) } //=> [2, 3, 4] ● ラムダ式は、文を手続き的に記述していく ● 関数参照は、宣言的な記述になる

Slide 8

Slide 8 text

2. レシーバが未定のメソッド参照

Slide 9

Slide 9 text

メソッド参照 ● メソッドのオブジェクトも取得できる ● この場合は、レシーバが未定 // 「型::メソッド名」という書式で取得 val foo: String.()->String = String::reversed // ^^^^^^^^^^^^^^^^^ 関数型 // メソッドっぽく呼び出せる "Kotlin".foo() //=> niltoK

Slide 10

Slide 10 text

拡張関数もOK fun String.bold(): String = "**$this**" val baz: String.()->String = String::bold "Sansan".baz() //=> **Sansan**

Slide 11

Slide 11 text

普通の関数型にもなるよ ● A.(B)->Cという型は、(A, B)->Cと同じっぽい fun String.bold(): String = "**$this**" // 型どっちでもOK val aaa: String.()->String = String::bold val bbb: (String)->String = aaa // 呼び出し方どっちでもOK "hoge".aaa() //=> **hoge** aaa("fuga") //=> **fuga**

Slide 12

Slide 12 text

高階関数で効果を発揮 "Hello".let { it.bold() } "Hello".let(String::bold) もしString.()->Stringが(String)->Stringと みなせなかったら、2行目の書き方がNGです。

Slide 13

Slide 13 text

3. レシーバが確定のメソッド参照

Slide 14

Slide 14 text

Bound Function Reference ● bound = 束縛された → レシーバが確定してるメソッド参照 ● Kotlin 1.1から使用できる

Slide 15

Slide 15 text

コード例 // 「オブジェクト::メソッド名」の書式で取得 val succ: (Int)->Int = 1::plus succ(5) //=> 6 userRepository.findById(123L) ?.let { user -> user.copy(blocked = true) } ?.let(userRepository::update)

Slide 16

Slide 16 text

4. プロパティも関数

Slide 17

Slide 17 text

プロパティも関数として扱える val prop: KProperty1 = String::length prop.get("Taro") //=> 4 val func: (String) -> Int = prop func("Taro") //=> 4

Slide 18

Slide 18 text

高階関数で効果を発揮 listOf("foo", "wa").map { it.length } // => [3, 2] listOf("foo", "wa").map(String::length) // => [3, 2] もしKProperty1が (String)->Stringとみなせなかったら、2行目の書き 方がNGです。

Slide 19

Slide 19 text

まとめ ● 関数オブジェクトを使うと宣言的な記述ができる ● ::hoge: 関数参照 ● Foo::bar: メソッド参照 ● foo::bar: レシーバ固定メソッド参照 (Bound Function Reference) ● プロパティも関数オブジェクトになれる