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

Takuji->find;

株式会社はてなでアプリケーションエンジニアやってます、技術的な記事を書いているつもり

Kotlin1.1の新機能についてざっと眺めてみた(M1-M3対応) #kansaikt

こんにちは、Kotlinエバンジェリストになりたいid:takuji31です。

先日EAPでM3が公開されたKotlin1.1の新機能について、あまりちゃんと把握していなかったのでM1から見直してみました。

なお、この内容の一部は Kansai.kt #2で発表されました。

各タイトルは公式ブログから

新機能

Coroutines

他の言語にある async/await とか generator/yield ですね。

非同期や反復処理をモダンな感じに書けるようになります。

Kotlin 1.1最大の新機能とも言えます。

使い方

coroutineは今はKotlin本体と分離されていて、別の依存を追加することで使えます。

compile 'org.jetbrains.kotlinx:kotlinx-coroutines-generate:0.1-alpha-2'
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-async:0.1-alpha-2'
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-rx:0.1-alpha-2'

それぞれ coroutines-asyncasync/awaitcoroutines-generategenerator/yieldcoroutines-rx が RxJavaのObservableをawaitできるライブラリーです。

async/await は誤解を恐れない書き方をすると、非同期な処理を実行したいメソッド内で async 関数を呼び、その中の非同期にやりたい処理をawait()で囲ってやります。 Observable の場合は async/await ではなく asyncRx/await(First|Last|Single) を使います。 await の引数は CompletableFuture なのでAndroidだと7.0以降(API24)、Javaだと8以降でしか使えません、残念。

めっちゃ雑なサンプル

fun asyncOperation(i: Int): CompletableFuture<Int> = CompletableFuture.supplyAsync {
    Thread.sleep(1000)
    i
}
val future = async<Int> {
    val i = await(asyncOperation(1))
    i
}
Log.d("MainActivity", "i:" + future.get())

雑に使ってみた感想だと、CompletableFutureをいい感じに使う機能でFutureあまり使わない勢からするとさほど利点はなさそうというイメージ、他言語のものほどはまだ洗練されてなさそうでした、まぁalpha2だしこんなもんでしょう。

Type aliases

型に別名を付ける機能です。 今まで(String, Int) -> Unitみたいな感じで書いていて面倒なのでわざわざinterface作っていたりしたコールバックとかをいい感じに名前つけられて便利。

typealias VeryUsefulAction = (String, Int) -> Unit

個人的に1.1の今のところ出ている新機能で一番ありがたいです。

Local delegated properties & Inline properties

関数とかメソッド内で使えるプロパティーらしい、関数内での初期化を簡単に書けたりするようになりそう?

いまいち使いどころがよく分からなかった。

Scripting

Kotlinでスクリプト書けるようになったらしいです、GradleがKotlinサポートを表明したのは記憶に新しいですが、これもその機能の1つのようです。

Generic Enum values access

Genericsを使っていい感じにEnumの値にアクセスできたりするらしいです、型引数と組み合わせると便利な処理が書けるようになったりしそう。 inline なのでコンパイル時にインライン展開してくれます。

inline fun <reified T : Enum<T>> enumValues(): Array<T>
inline fun <reified T : Enum<T>> enumValueOf(name: String): T

新たな文法

Bound callable references

いわゆるmethod referenceみたいなやつですね、今までは Class.method をサポートしていたけど、新たに variable.method もサポートするとのことです。

Destructuring in Lambdas (M2)

合成値(data classとかPairみたいにvariable.component1()...componentN()で分解できるやつ)の分解を、ラムダ式でもいい感じにやってくれるようになりました。

listOf(Pair(1, 2), Pair(2,3)).map{
    (a, b) -> a + b // 3, 5
};

今までは面倒だけど変数定義し直していたりしたので、簡単に書けるようになって便利ですね。

Underscore for unused symbols (M3)

使わない戻り値を_で無視することのできる機能

ラムダ式の引数を無視したり、合成値の分解をした時に途中の値だけ捨てるのに便利ですね。

data class User(val id: Long, val name: String)
// ...
val (_, name) = user;

Underscore in numeric literals (M3)

数値リテラルの途中に_を挟めるようになりました。10000000 -> 10_000_000 みたいな感じ。

Perlで見たことあるやつって感じで桁の多い数値を表現する時に便利ですね。

その他変更

Relaxed rules for sealed classes and data classes

sealed classやdata classの定義が柔軟になったとのこと。

data class は非data classを継承できるようになっています。 もちろんopenである必要があるし、プロパティーもopenじゃないと継承できません。

open class User(open val id: Long, open val name: String)

data class AdminUser(override val id:Long, override val name: String, val role: String) : User(id = id, name = name)

これは結構ありがたい。

sealed classは今までは必ず子クラスは親の中で定義する必要があった(sealed A を継承する場合は A.B)のですが、これが不要になり、同じファイル内ならどこに書いても良いことになりました。

sealed class Score(val number: Int)

class Strike() : Score(10)
class Gutter() : Score(0)
class Miss() : Score(0)

importする時に若干面倒だったのでありがたいですね。

Java 7/8 support

Kotlin1.1からJava7/8がサポートされました。

ちゃんとJavaの新しいクラスなんかもKotlinで使えます。

JavaScript

JSサポートが強化されているらしいですが、使ってるのを聞いたことがないのでよく分かりませんでした。

眺めてみて

結構色々便利にはなっていますが、どれもまだEAPなので変わる可能性はありますし、今後もっと増えるかもしれません。

余談ですが、IDEAの2016.3で1.1M3のプラグインがまともに動かなかったので、Android Studioを使ってAndroidアプリで試しました。