2016/12/20の30分 Kotlinメモ👽

2016/12/20の30分 Kotlinメモ👽

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

github.com

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

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

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

Closures

Closuresなんぞ?という話は以下でなんとなくわかる。

qiita.com

getCounterメソッド内で宣言してるcount変数をreturnのLambdaの中で参照・変更できている。

要はLambdaの外側の関数で宣言されている変数の参照・変更ができる。

以下ではgetCounterを呼び出すごとに値がインクリメントされてるので、状態を保持することができる関数とも言えるのかな?

fun getCounter(): () -> Int {
    var count = 0

    return {
        count++
    }
}

println(counter()) // 0
println(counter()) // 1
println(counter()) // 2

Javaだと参照はできるけど、変更はできない。

var sum = 0
(1..10).forEach {
    sum += it
}
println(sum)

// Java
int sum = 0;
Stream.of(1, 2, 3)
        .forEach(integer -> {
            // Lambdaから外の変数の変更はできない
            sum += integer;
        });

public Supplier<Integer> getCounter() {
    int count = 0;
    return () -> {
        // Lambdaから外の変数の参照は可能
        return count;
    };
}

うむ。なのでJavaのLambdaはClosuresではない!と言われてるわけだ。

d.hatena.ne.jp

Closuresにあまり慣れていないからどういう場合に有効なのかは今後考えてみる

Inline Functions

kotlinlang.org

インライン展開することを意識して書く必要があるのね。

確かにKotlinの標準ライブラリはめっちゃinline付いてるなーと思ってたけど理由がなんとなくわかった。

// インライン関数
// 引数の関数オブジェクトがコンパイル時にインライン展開される
inline fun log(debug: Boolean = true, message: () -> String) {
    if (debug) {
        println(message())
    }
}

log { "debug log" }
log(false) { "debug log" }

crossinlineとかもいくつか使われてるの見たことあるなー

Non-local returns

Kotlin本では非ローカルリターンとラベルへのリターンと書いてある。

Lambdaの中でreturnすると関数から抜けるのね。

inline fun stringForEach(str: String, f: (Char) -> Unit) {
    for (c in str) f(c)
}

fun containsDigit(str: String): Boolean {
    stringForEach(str) {
        if (it.isDigit()) {
            println("containsDigit true")
            return true
        }
    }
    println("containsDigit false")
    return false
}

containsDigit("aaaaa") // containsDigit false
containsDigit("aaa1aa") // containsDigit true

Lambda自身から抜けたい時はラベルへのリターンを使えってことね。

ラベル名は自分でも付けられるけど、推論できる場合は関数名を指定できるらしい。

さっきのコードは結果がどうだったかを出力するのに2箇所にpirntln書いてたけど、ラベルへのリターンを使えば出力を1箇所に集約できる。

fun containsDigit2(str: String): Boolean {
    var result = false
    stringForEach(str) {
        if (it.isDigit()) {
            result = true
            return@stringForEach
        }
    }
    println("containsDigit $result")
    return result
}

containsDigit2("aaaaa") // containsDigit false
containsDigit2("aa1aaa") // containsDigit true

ラベルを自分でつけるならこんな感じ。

fun containsDigit3(str: String): Boolean {
    var result = false
    stringForEach(str) here@ {
        if (it.isDigit()) {
            result = true
            return@here
        }
    }
    println("containsDigit $result")
    return result
}

まとめ

30分以上やってますよ...はい...👽

2016/12/19の30分 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() }

まとめ

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

2016/12/18の30分 Kotlinメモ🍓

2016/12/18の30分 Kotlinメモ

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

github.com

スコープ関数

このQiitaがすごくよくまとまってる。

ありがたし。

qiita.com

調べる前にwithというものがあることを知り、どう使うのがいいのかなーと考えてみた。

Qiitaの記事を読んでみて、withならStringBuilderとかに使うとどうかなー?と思ってコードを書いてみた。

val strstr = with(StringBuilder()) {
    append("test")
    append("hunhun")
    toString()
}
println(strstr) // testhunhun

うーん、まあ良さ気?なのか?

とりあえずapplyletrunなどもどう使い分けるべきなのかがなんとなくだけどわかったので良かったっす!

Kotlin Night Riga

Kotlin Night Rigaの資料 2つ見てみた。

両方ともわりと初心者向けっぽい資料だった。

読んでてほとんど内容理解できたので、あーKotlin少しわかってきたのかな?という感覚を覚えたが、それはないな...🍓

jug.lv

docs.google.com

github.com

まとめ

そろそろ目的意識を持ってコード書き始めたほうがいいのかなーと思ってきた今日此の頃です

Kotlinの情報を集めるぞい! - 2016/12/17の30分 Kotlinメモ🙉

2016/12/17の30分 Kotlinメモ🙉

もっとKotlinに関する情報が欲しくなってきたので、情報源をあさってみるぞ!

Kotlin Twitter

とりあえずチェックしておくと良さそう。

twitter.com

The Daily Kotlinというのも一応みておこう。

twitter.com

Kotlin Blog

公式Blogはまず見ておいた方が良さそう。RSSとかに登録すればOKOK!

blog.jetbrains.com

Qiita Kotlin tag

QiitaのKotlin tagもRSSとかに登録しておいて気になったの見れば良さそう!

qiita.com

mediumにもKotlin tagあるので、気になる人はこっちも見ると良さそう!

medium.com

Awesome Kotlin

Kotlinに関する情報が色々あるやーつ。

libraryからKotlinに関する記事、動画まで色々まとまってる。

github.com

以下のページからawesome-kotlinにまとまってる内容をfilterできるので、めっちゃ便利!!

Kotlin is Awesome!

アドベントカレンダー

2016年はまだ途中ですが、歴代のアドベントカレンダーから得られる情報もあるよね!

qiita.com

www.adventar.org

www.adventar.org

www.adventar.org

atnd.org

Kotlin Weekly

Android Weekly的なあれですね。RSSに登録しておくよ良さそう!

us12.campaign-archive2.com

たろーさん情報

Kotlinエバンジェリストのたろーさん情報が気になるなら、とりあえずTwitter + Blog + Speakerdeckとか見るよ良さそう。

SpeakerdeckにいっぱいKotlin話があって見てると面白いぞ!

twitter.com

taro.hatenablog.jp

Presentations by Taro Nagasawa // Speaker Deck

その他

Kotlin forumがあったり、Slackがあったりするよ。

そこら辺以下にまとまってるよ!

kotlinlang.org

日本のSlackもあるよ!

Join kotlinlang-jp on Slack!

まとめ

情報源がもっと増えてくれると嬉しいぞい!

2016/12/16の30分 Kotlinメモ👌

2016/12/16の30分 Kotlinメモ👌

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

github.com

Kotlinスタートブック -新しいAndroidプログラミング が手元に届いたので、読み始めてる。

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

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

Iterator

KotlinのIteratoriteratorメソッドを持つオブジェクトは、Iteratorを提供することになるらしい。

iteratorメソッドは、operator fun hasNext(): Booleanoperator fun next():Tを持つオブジェクトを返す必要がある。

何も実装なり継承なりしなくてよいと。これって要はduck typingなのかな?

class MyIterator {
    var i = 0
    operator fun hasNext(): Boolean = i++ < 5
    operator fun next(): String = "next"
}

class MyIterable {
    operator fun iterator() = MyIterator()
}

for (item in MyIterable()) {
    println(item)
}

Tail recursive functions

kotlinlang.org

再帰呼び出しの最適化の話。

KotlinはTCO(Tail Call Optimization)の仕組みがあるらしい。

末尾呼出し最適化とか言う場合もあるのかな?助けてウィキペディア先生!!

末尾再帰 - Wikipedia

再帰呼び出しってスタック積むやん、あれ最適化できるで!程度の理解でもういんじゃね?適当で。

とりあえず数値Listの合計を求める関数sumを作るとして、スタックさいならするコードが以下ですよーと。

うむ、どんどんスタック積まれていきますなー。

fun sumsum(numbers: List<Long>): Long = if (numbers.isEmpty()) 0 else numbers.first() + sum(numbers.drop(1))

sumsum((1L..10000000).toList())

んでKotlinでは「関数の最後の計算を再帰呼び出しにする」ことで、tailrec modifierが付けられると。

tailrecをつけることで、最適化されますよーってことらしい。なるほど。

んで書き直したのが以下。関数の最後がsum関数を呼び出すようになってる = 関数の最後の計算を再帰呼び出しにする になってますね。

tailrec fun sum(numbers: List<Long>, accumulator: Long = 0): Long = if (numbers.isEmpty()) accumulator else sum(numbers.drop(1), accumulator + numbers.first())

sum((1L..10000000).toList())

まとめ

Kotlin色々あるなー