100 言語 Speedrun: エピソード 05: Kotlin


Kotlin は Java にとって、ES6 が古いスタイルの JavaScript にとってあるようなものです.多くの人が JavaScript エンジン (ブラウザーなど) や JVM (Android など) に行き詰まっています.彼らの母国語はひどいものですが、完全に非母国語を使用すると、ネイティブ API とのインターフェースが非常に複雑になります.そのため、JavaScript 用の ES6 や Java 用の Kotlin などの妥協案が作成されました. Kotlin は Android 開発者の間で特に人気がありますが、JVM を使用できる場所ならどこでも使用できます.また、最近では「プレーンな Java」を使用する正当な理由を見つけるのが本当に難しくなっています.

こんにちは世界



いつものプログラムからスタート!普通の Java でそれがどれほど悪かったかを覚えていない限り、これは何も珍しいことではありません.

fun main() {
  println("Hello, World!")
}


残念ながら、これを実行するには、このばかげた行を実行する必要があります.私のラップトップで 7 秒という妥当な hello world を実行するには、全体に時間がかかりすぎます.

$ kotlinc hello.kt -include-runtime -d hello.jar && java -jar hello.jar


Java の世界では、合理的な起動時間について、私とはまったく異なる期待があります. Kotlin にはある種の「スクリプト モード」と REPL があり、IDE と統合できるため、日常的にコーディングする人にとってはそれほど問題ではないかもしれません.
./run file.kt を許可する短いスクリプトをコード リポジトリに含めました.

フィボナッチ



悪くない.推論可能であるように思われるいくつかの型注釈が必要ですが、それはすべて完全に合理的なコードです.私が要求しすぎていると思われる場合は、Crystal に到着するまで待ってください.しかし、多くの言語は fibIntInt であることを理解できます.

範囲ループの構文は完全に読みやすく、基本的に内部の Java であることを考えると、全体的に驚くほど読みやすく、簡潔なコードです.

fun fib(n: Int): Int {
  if (n < 3) {
    return 1
  } else {
    return fib(n - 1) + fib(n - 2)
  }
}

fun main() {
  for (i in 1..30) {
    println(fib(i))
  }
}


フィズバズ



Kotlin は C スタイルの switch を捨て、代わりに when 構文を導入しました.これは、漠然と Haskell スタイルのパターン マッチングに似ています.

fun fizzbuzz(n: Int): String {
  return when {
    n % 15 == 0 -> "FizzBuzz"
    n % 3 == 0 -> "Fizz"
    n % 5 == 0 -> "Buzz"
    else -> n.toString()
  }
}

fun main() {
  for (i in 1..100) {
    println(fizzbuzz(i))
  }
}


ユニコード



Kotlin は基本的に内部では Java であるため、ベース プレーンの外ではまだ Unicode を正しく処理できないため、最後の答えは間違っています.

fun main() {
  println("Hello".length)
  println("Źółw".length)
  println("💩".length)
}


それは印刷します:

5
4
2


データクラス



Java を使用すると、ほぼすべての種類のデータを操作するのが非常に面倒になります.すべての単純なデータ クラスには、明示的なコンストラクター、ゲッター、セッター、ハッシュコード、および等号が必要です. == を使用することさえできず、 .equals() を実行する必要がありますが、片側が null の場合は文字通りクラッシュするため、最初に両側を null チェックしてから .equals() をチェックする必要があります.基本的なデータ操作のための定型文のばかげた量です.

Kotlin は、このでたらめのほとんどすべてを回避します.

data class Point(val x: Double, val y: Double) {
  fun length() = Math.sqrt(x * x + y * y)
}

fun main() {
  val a = listOf(1, 2, 3)
  val b = listOf(1, 2, 3)
  val c = Point(30.0, 40.0)
  val d = Point(30.0, 40.0)

  println(a == b)
  println(c == d)
  println(null == d)
  println("len of ${c} is ${c.length()}")
}


どちらが印刷されますか:

true
true
false
len of Point(x=30.0, y=40.0) is 50.0

listOf(1, 2, 3) の代わりに [1, 2, 3] を実行する必要がありました.

関数型プログラミング



そして、Kotlin で Point(30, 40)map 、および filter をどのように行うのでしょうか? reduce 個のブロックを持つ Ruby のように見えます.興味深いことに、引数なしでブロックを渡すと、デフォルトが { arguments -> ... } であるかのように扱われます.これはめったにない機能で、特に Perl で見られるもので、やや不可解な { it -> ... } と呼ばれています.

fun main() {
  val alist = listOf(1, 2, 3, 4, 5)

  println(alist.map{ x -> x * 2 })
  println(alist.map{ it * 2 })
  println(alist.filter{ it % 2 == 1 })
  println(alist.reduce{ a, b -> a + b })
}


それは期待されるものを生成します:

[2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]
[1, 3, 5]
15


Java を使用する必要がありますか?



普段なら「Kotlinを使ったほうがいいですか」と聞くんですが、それは逆の見方です.本当の質問は「Java を使用する必要があるか」であり、答えは明確で明確な NO です. JVM で何かを実行し、「Java」エコシステムと対話する必要がある場合は、言語の悲惨な言い訳に触れることなくこれを行うことができます. Kotlin は Java にとって、ES6 が古いスタイルの JavaScript に対してどのようなものであったかを示していますが、ここでの改善ははるかに大きくなっています.古いスタイルの JavaScript は死に、ES6+ JavaScript に完全に置き換えられました.これは、Java にも降りかかる運命です.

JRuby、Clojure、Scala などのような JVM 言語は他にもありますが、それらは本質的に異なる言語であり、セマンティクスが異なり、相互運用性の話もさまざまです. Kotlin は固定 Java であり、それ以上でもそれ以下でもありません.

したがって、決して Java を使用しないでください.

コード



All code examples for the series will be in this repository.

Code for the Kotlin episode is available here.