読者です 読者をやめる 読者になる 読者になる

2016/12/19の30分 Kotlinメモ🍭

Kotlin

2016/12/19の30分 Kotlinメモ🍭

書いてるコードは雑にここにあります。

github.com

Kotlinスタートブック -新しいAndroidプログラミング を引き続き読んでる。

Kotlinスタートブック -新しいAndroidプログラミング

Kotlinスタートブック -新しいAndroidプログラミング

Higher-Order Functions and Lambdas

kotlinlang.org

関数オブジェクトとか関数型とか高階関数とかLambdaとかそこら辺の話。

前回読んだ時はちんぷんかんぷんだったけど、ちょっとわかってきたかも。

fun mumu(i: Int): Int {
    return i * 2
}

// 関数オブジェクト
val mumu = ::mumu
println(::mumu)


// 関数オブジェクトの型
// (引数の型) -> 戻り値の型
val mumu2: (Int) -> Int = ::mumu
println(mumu(2))

Higher-Order Functions

関数を引数で受け取ったり、戻り値をして返すような関数を高階関数というらしい。

以下のように文字列から特定の条件にマッチした位置を返す関数があるとして、特定の条件ごとに関数を書いていくと。

fun firstK(str: String): Int {
    tailrec fun go(str: String, index: Int): Int =
            when {
                str.isEmpty() -> -1
                str.first() == 'K' -> index
                else -> go(str.drop(1), index + 1)
            }
    return go(str, 0)
}

fun firstUpperCase(str: String): Int {
    tailrec fun go(str: String, index: Int): Int =
            when {
                str.isEmpty() -> -1
                str.first().isUpperCase() -> index
                else -> go(str.drop(1), index + 1)
            }
    return go(str, 0)
}

println(firstK("aaaKaaa")) // 3
println(firstUpperCase("aaaAaaa")) // 3

特定の条件って部分を関数として受け取ればよくね?って話。なるほどー

// firstKとfirstUpperCaseの条件部分を関数オブジェクト化
fun first(str: String, predicate: (Char) -> Boolean): Int {
    tailrec fun go(str: String, index: Int): Int =
            when {
                str.isEmpty() -> -1
                predicate(str.first()) -> index
                else -> go(str.drop(1), index + 1)
            }
    return go(str, 0)
}

fun firstK2(str: String): Int {
    fun isK(c: Char): Boolean = c == 'K'
    return first(str, ::isK)
    // 以下のように直で書いてもよい
//    return first(str, fun(c: Char): Boolean = c == 'K')
    // lambda式
//    return first(str, { it == 'K' })
}

fun firstUpperCase2(str: String): Int {
    fun isUpperCase(c: Char): Boolean = c.isUpperCase()
    return first(str, ::isUpperCase)
    // 以下のように直で書いてもよい
//    return first(str, fun(c: Char): Boolean = c.isUpperCase())
    // 以下のように型を省略しても書ける
//    return first(str, fun(c) = c.isUpperCase())
    // 以下のようにも書ける
//    return first(str, Char::isUpperCase)
}

println(firstK2("aaaKaaa")) // 3
println(firstUpperCase2("aaaAaaa")) // 3

Lambda

Lambdaなら一々::とか書かなくても関数オブジェクト作れるよーって話。

it便利!

// lambda式
// 関数オブジェクトを直接生成する
val jijijiji: (Int) -> Int = { i: Int ->
    i * i
}
println(jijijiji(2)) // 4

// 型は省略できる 
val jijijiji2 = { i: Int ->
    i * i
}
println(jijijiji2(2)) // 4

// 引数が1つの場合、itを使える
val jijijiji3: (Int) -> Int = {
    it * it
}
println(jijijiji3(2)) // 4

さらにLambdaを使って、文字列の中の最初の空白文字の位置を見つける関数を書いてみると。

fun firstWhitespace(str: String): Int = first(str, { it.isWhitespace() })

// 最後の引数がlambdaを取るような関数なら、以下にようにも書ける
fun firstWhitespace2(str: String): Int = first(str) { it.isWhitespace() }

まとめ

雑な理解で雑なコードを書いていくぞい!!