LoginSignup
50
39

More than 5 years have passed since last update.

Kotlinの関数参照 #Kotlin_Sansan

Last updated at Posted at 2017-04-04
1 / 20

はじめに

この記事は第5回Kotlin勉強会@Sansanの発表で使用した内容です。


自己紹介


もくじ

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

1. 関数参照


関数オブジェクト

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

コード例

// 普通の関数
fun succ(n: Int): Int = n + 1

// 関数オブジェクトを取得し、変数に代入
val myFunc: (Int)->Int = ::succ
//          ^^^^^^^^^^ 関数型

// メソッド呼び出しによる元の関数の計算を実行
myFunc.invoke(5) //=> 6

// 演算子オーバロードによる関数らしい記述
myFunc(7) //=> 8

応用例

// 高階関数の引数に「関数参照」を渡す
listOf(1, 2, 3).map(::succ) //=> [2, 3, 4]

// ラムダ式を使えば同じ
listOf(1, 2, 3).map { succ(it) } //=> [2, 3, 4]
  • ラムダ式は、文を手続き的に記述していく
  • 関数参照は、宣言的な記述になる

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


メソッド参照

  • メソッドのオブジェクトも取得できる
  • この場合は、レシーバが未定
// 「型::メソッド名」という書式で取得
val foo: String.()->String = String::reversed
//       ^^^^^^^^^^^^^^^^^ 関数型

// メソッドっぽく呼び出せる
"Kotlin".foo() //=> niltoK

拡張関数もOK

fun String.bold(): String = "**$this**"
val baz: String.()->String = String::bold
"Sansan".baz() //=> **Sansan**

普通の関数型にもなるよ

  • 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**

高階関数で効果を発揮

"Hello".let { it.bold() }
"Hello".let(String::bold)

もしString.()->String(String)->Stringとみなせなかったら、2行目の書き方がNGです。


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


Bound Function Reference

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

コード例

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

4. プロパティも関数


プロパティも関数として扱える

val prop: KProperty1<String, Int> = String::length
prop.get("Taro") //=> 4

val func: (String) -> Int = prop
func("Taro") //=> 4

高階関数で効果を発揮

listOf("foo", "wa").map { it.length }   // => [3, 2]
listOf("foo", "wa").map(String::length) // => [3, 2]

もしKProperty1<String, Int>(String)->Stringとみなせなかったら、2行目の書き方がNGです。


まとめ

  • 関数オブジェクトを使うと宣言的な記述ができる
  • ::hoge: 関数参照
  • Foo::bar: メソッド参照
  • foo::bar: レシーバ固定メソッド参照 (Bound Function Reference)
  • プロパティも関数オブジェクトになれる
  • 次に見るべきスライド?(ネタ枠)
50
39
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
39