Help us understand the problem. What is going on with this article?

Kotlinの関数参照 #Kotlin_Sansan

More than 3 years have passed since last update.

Kotlinの関数参照 #Kotlin_Sansan

by ngsw_taro
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)
  • プロパティも関数オブジェクトになれる
  • 次に見るべきスライド?(ネタ枠)
ngsw_taro
自称Kotlinエバンジェリスト
https://taro.hatenablog.jp/
dr-ubie
病気予測AIによる病院向け問診サービス、及び to C 向け病気予測サービスを運営するスタートアップ
https://ubie.life/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした