算譜王におれはなる!!!!

偏りはあると思うけど情報技術全般についてマイペースに書くよ。

Kotlin M13で追加されたlateinit試してみた

Kotlin マイルストーン13 がリリースされました!

blog.jetbrains.com

その中で追加されたlateinitというプロパティにつける修飾子が便利そう。 プロパティの初期化を先延ばしにできるので既存のフレームワークにインジェクトしてもらえるって寸法です。

「プロパティの初期化の先延ばし」っていうとDelegated propertyを思い出すけど、これには問題があったのでした。。

ということでlateinitを試してみました。

import com.google.inject.Guice
import javax.inject.Inject
import kotlin.properties.Delegates

class Greeter {
  fun greet() {
    println("Hello")
  }
}

class Client {
  @Inject
  lateinit val greeter1: Greeter

  @Inject
  val greeter2: Greeter by Delegates.notNull()
}

fun main(args: Array<String>) {
  val injector = Guice.createInjector()
  val client = injector.getInstance(Client::class.java)
  client.greeter1.greet() //=> Hello
  client.greeter2.greet() // IllegalStateException thrown
}

Google Guiceでインジェクトしています。 lateinitが付いているgreeter1は見事インジェクトされています!しかし、Delegates.notNull()をつけているgreeter2はインジェクトされておらずgreet()呼び出し時に初期化が済んでないよと例外が投げられてしまいました。

そのほかの変更点についてはまた後ほど。

ちなみにこれならいける

var greeter2: Greeter by Delegates.notNull()
  @Inject set

第3回かわいいKotlin勉強会を開催しました #jkug

kotlin.doorkeeper.jp

開催しました!!!

第3回です!!

44名の方にご来場いただきました。 申し込み自体はキャンセル混みで86名です。 すごい人気です。

会場をご提供してくださいましたドリコム様(@sue445さん)、 運営スタッフの@yy_yankさんにこの場をお借りして感謝申し上げます。

発表資料

Kotlinらしいコード (私)

Server Side Kotlin (@yy_yankさん)

個人開発AndroidアプリをKotlinにガチ移行してみた話 (@kiriminさん)

Kotlin as an AltJS (@mike_neckさん)

(あやぴーさん)

普段C#使っている僕から見た、Kotlin (@RyotaMurohoshiさん)

Kotlin M12 言語仕様変更のまとめ

ついにKotlinマイルストーン12がリリースされました! 公式ブログはこちら。 言語仕様の変更についてまとめます。 今回はわりと多いです。

アノテーション

アノテーションの記法がJavaっぽくなりました。 つまりM12より前では[Foo(args)]と書いていたものを、M12以降では@Foo(args)と書くことになります。 今まで通り@を付けずに済むこともあります。

ラベル

このアノテーションの変更に伴い、ラベルの書き方も変わります。 今までは@nameだったものをname@@を最後に持ってくる必要があります。

loop@ for (i in 1..100) {
  for (j in 1..100) {
    if (...)
      break@loop
  }
}

アノテーションでKClassが使えるようになった

アノテーションの引数として受け取るクラス参照が、M12より前だとjava.lang.Class限定でした。 そのため引数を渡す側のコードはjavaClass<MyClass>()のようなちょっとイケてない記述になっていました。 M12からはjava.lang.Classの代わりにkotlin.refrect.KClassが使えるようになります。

プライマリコンストラクタ

今までプライマリコンストラクタclass User(val id: Long)のように記述していました。 M12でもこの記法は有効ですが、full formで記述するとclass User constructor(val id: Long)になります。 このfull formは、プライマリコンストラクタに対してアノテーションや修飾子を付けるときに使用することになります。

インタフェース

traitキーワードは非推奨となり、interfaceキーワードに取って代わられます。

列挙型

Javaenumと非常に近くなりました。 つまり、エントリ間はカンマで区切り、メンバを持たせる場合には最後のエントリにセミコロンを置き、エントリの直後にコンストラクタへのパラメータリストを記述できるようになりました。詳細はこちら

関数型

通常の関数型が要求される場面で、拡張関数を渡せるようになったらしいです。メソッド参照がJavaのそれと同じような感じになったということです。具体的には(String) -> Intが要求される箇所でString::lengthのようなString.() -> Int型の関数参照を渡せます。

// M12より前はこう書いてた
strs.map { it.length() }

// M12からはこう書ける (M12より前は型エラーになってた)
strs.map(String::length)

KotlinでJavaみたいなメソッド参照をする - 算譜王におれはなる!!!!で面白い(けど複雑な)アプローチを考えていたのでこの改善は嬉しいです!

スマートキャスト

スマートキャスト(nullチェック含む)がより賢くなりました。 varな変数に対してもコンパイラが追える範囲で、スマートキャストが有効になります。

名前付きリターン

高階関数の引数として直接記述する関数式内での名前付きリターンがサポートされたようです(M11でもされてたような?)。 関数式はfun(arg)=...のように書く関数リテラルみたいなやつのことです。

削除された機能と非推奨になった機能

削除

  • class object。代わりにcompanion objectを使いましょう。
  • 匿名イニシャライザ。initを付けたブロックを使いましょう。

非推奨

  • whenでのbreakcontinue
  • インタフェースのクラス継承
  • スーパタイプの共変特殊化
  • 静的型の表明

(ネタ)Kotlinで暗黙の引数いろいろ

Kotlinの関数リテラルはその引数が唯一つだけの場合、暗黙の引数としてitが使用できるのはみなさんご存知だと思います(暗黙の引数という言葉は正確じゃないような気がするけど気にしない)(知らない人は公式ドキュメントか今日発売のSoftwareDesignを見るといいよ)。

listOf(1, 2, 3, 4, 5)
  .filter { n -> 2 < n } // 引数を明示することも
  .map { it * 2 }        // itを使うこともできる。
  .let { println(it) }   // => [6, 8, 10]

Scalaっぽく

Scalaの関数リテラルの暗黙の引数は、複数の引数に対応しています。それぞれ_で参照することになりますが、参照するたびに第一引数、第二引数のように変化します。

// Scala
Seq(1, 2, 3).reduce(_ + _)

こういう感じの暗黙の引数がKotlinにも欲しかったので作ってみました。

// Scalaっぽい暗黙の引数_が使える(Int, Int)->Intな関数のためのクラス
class ScalaFunc2(val a: Int, val b: Int) {
    var count: Int = 0
    
    val _: Int
    get() = when(count++) {
        0 -> a
        1 -> b
        else -> throw IllegalStateException()
    }
}

そして独自のreduceを定義。

fun List<Int>.myReduce(f: ScalaFunc2.()->Int): Int =
    reduce { a, b -> ScalaFunc2(a, b).f()}

fScalaFunc2の拡張メソッドです。 そして実際に使ってみる!

listOf(1, 2, 3).myReduce{_ + _}

成功です! しかし残念なことにScalaFunc2<A, B, C>のように一般化できません。 ScalaFunc2_プロパティが参照されるたびにその型を変化させることができないからです。

Clojureっぽく

Clojureの無名関数における暗黙の引数も複数の引数に対応しています。 第一引数は%1、第二引数は%2という具合で参照できるので引数の呼び出し順序とか回数とかを気にせずに使用できます。

; Clojure
(reduce #(+ %1 %2) [1, 2, 3])

; わざわざ無名関数定義せず+だけでいいんだけどいい例が思いつかず...

これをKotlinで。

// Clojureっぽい暗黙の引数が使える(A, B)->Cな関数のためのクラス
class ClojureFunc2<A, B>(val _1: A, val _2: B)

fun <A> List<A>.myReduce(f: ClojureFunc2<A, A>.()->A): A =
    reduce { a, b -> ClojureFunc2<A, A>(a, b).f() }

今回は型を一般化できました。

listOf(1, 2, 3).myReduce{_1 + _2}

以上です。