Upgrade to Pro — share decks privately, control downloads, hide ads and more …

コードで見るKotlin 1.3

Avatar for Kohei Yamato Kohei Yamato
November 07, 2018

コードで見るKotlin 1.3

Avatar for Kohei Yamato

Kohei Yamato

November 07, 2018
Tweet

More Decks by Kohei Yamato

Other Decks in Programming

Transcript

  1. 自己紹介 • 大和 康平 (24) • エムスリー 2018年4月入社 • 仕事の担当:

    サーバーサイド • 趣味: モータースポーツ観戦
  2. 発表の概要 • 基本的にはこちらの内容 ◦ What's New in Kotlin 1.3 (https://kotl.in/1.3)

    • この中から3つをピックアップして紹介 ◦ Coroutines (ごく一部) ◦ Inline Classes ◦ Standard Libraries
  3. launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")

    } println("Hello,") Thread.sleep(2000L) } メインスレッドをブロックしない が1000ms停止
  4. launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")

    } println("Hello,") Thread.sleep(2000L) } 先に実行される
  5. launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")

    } println("Hello,") Thread.sleep(2000L) } => Hello, World!
  6. launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")

    } println("Hello,") Thread.sleep(2000L) } => Hello, World! 2000ms停止することで待 ち合わせ
  7. launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")

    } println("Hello,") } => Hello, 実行される前に終了
  8. Job fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")

    Thread.sleep(2000L) } coroutineの内容によらず 2000ms停止......
  9. Job fun main() { val job = GlobalScope.launch { delay(1000L)

    println("World!") } println("Hello,") job.join() }
  10. Job • launch coroutine builder の返り値 • いくつかの状態を持つ ◦ New,

    Active, Completing, Cancelling, Cancelled, Completed • Job#join を実行することにより、完了するまで呼び出し元 の coroutine を停止できる
  11. Job fun main() { val job = GlobalScope.launch { delay(1000L)

    println("World!") } println("Hello,") job.join() } coroutineが完了するまで待ち合わせ
  12. Job fun main() { val job = GlobalScope.launch { delay(1000L)

    println("World!") } println("Hello,") job.join() } => Hello, World!
  13. runBlocking coroutine builder fun main() { val job = GlobalScope.launch

    { delay(1000L) println("World!") } println("Hello,") job.join() }
  14. runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")

    } println("Hello,") } 完了するまでメインスレッドをブ ロック
  15. CoroutineScope fun main() { val job = GlobalScope.launch { delay(1000L)

    println("World!") } println("Hello,") job.join() }
  16. CoroutineScope fun main() = runBlocking { val job = GlobalScope.launch

    { delay(1000L) println("World!") } println("Hello,") job.join() }
  17. CoroutineScope fun main() = runBlocking { // this: CoroutineScope launch

    { delay(1000L) println("World!") } println("Hello,") }
  18. CoroutineScope • 全ての coroutine builder は、そのコードブロックのスコープ に CroutineScope のインスタンスを追加する •

    外のコルーチンは、スコープ中で起動されたコルーチンが全 て終了するまで完了しない
  19. CoroutineScope fun main() = runBlocking { launch { delay(1000L) println("World!")

    } println("Hello,") } => Hello, World! coroutine が完了するまで アプリケーションは終了しない
  20. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L) 10 } println(x.await()) }
  21. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L) 10 } println(x.await()) } async による coroutine
  22. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L) 10 } println(x.await()) } coroutine の完了まで待つ
  23. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L) 10 } println(x.await()) } => 10 (約1秒後)
  24. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
  25. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
  26. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
  27. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } 最大2000ms停止
  28. async coroutine builder fun main() = runBlocking { val x

    = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } => 30 (約2秒後)
  29. async coroutine builder fun main() = runBlocking { val time

    = measureTimeMillis { val x = async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } println("$time ms") } => 30 2033 ms 時間計測しても約2000ms
  30. Coroutines まとめ • Coroutine builder を使用して作成する ◦ launch ◦ runBlocking

    ◦ async • 階層構造を持たせて実行するとよい
  31. プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val

    securePassword = Password("Don't try this in production") println(securePassword.value) }
  32. プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val

    securePassword = Password("Don't try this in production") println(securePassword.value) } プロパティを1つ持つ Inline Class
  33. プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val

    securePassword = Password("Don't try this in production") println(securePassword.value) } 通常の Class として利用できる
  34. プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword

    = Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } Java に逆コンパイルした main 関数
  35. プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword

    = Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } プロパティの型が返る
  36. プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword

    = Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } static method として実行される
  37. プライマリコンストラクタのみ (decompiled) public final class Password { @NotNull public static

    String constructor_impl/* $FF was: constructor-impl*/(@NotNull String value) { Intrinsics.checkParameterIsNotNull(value, "value"); return value; } } 逆コンパイルした Inline class
  38. プライマリコンストラクタのみ (decompiled) public final class Password { @NotNull public static

    String constructor_impl/* $FF was: constructor-impl*/(@NotNull String value) { Intrinsics.checkParameterIsNotNull(value, "value"); return value; } } 引数をそのまま返す
  39. プロパティ&メソッド inline class Name(val s: String) { val length: Int

    get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) }
  40. プロパティ&メソッド inline class Name(val s: String) { val length: Int

    get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) } 引数は1つのみ
  41. プロパティ&メソッド inline class Name(val s: String) { val length: Int

    get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) }
  42. プロパティ&メソッド inline class Name(val s: String) { val length: Int

    get() = s.length fun greet() { println("Hello, $s") } } fun main() { val name = Name("Kotlin") name.greet() println(name.length) } それぞれ単純な処理
  43. プロパティ&メソッド (decompiled) public static final void main() { String name

    = Name.constructor-impl("Kotlin"); Name.greet-impl(name); int var1 = Name.getLength-impl(name); System.out.println(var1); }
  44. プロパティ&メソッド (decompiled) public static final void main() { String name

    = Name.constructor-impl("Kotlin"); Name.greet-impl(name); int var1 = Name.getLength-impl(name); System.out.println(var1); } static method で String を返す
  45. プロパティ&メソッド (decompiled) public static final void main() { String name

    = Name.constructor-impl("Kotlin"); Name.greet-impl(name); int var1 = Name.getLength-impl(name); System.out.println(var1); } コンストラクタと同様に static method が呼ばれる
  46. プロパティ&メソッド (decompiled) public final class Name { public static final

    int getLength_impl/* $FF was: getLength-impl*/(String $this) { return $this.length(); } public static final void greet_impl/* $FF was: greet-impl*/(String $this) { String var1 = "Hello, " + $this; System.out.println(var1); } }
  47. プロパティ&メソッド (decompiled) public final class Name { public static final

    int getLength_impl/* $FF was: getLength-impl*/(String $this) { return $this.length(); } public static final void greet_impl/* $FF was: greet-impl*/(String $this) { String var1 = "Hello, " + $this; System.out.println(var1); } } length() を呼び出すだけ
  48. プロパティ&メソッド (decompiled) public final class Name { public static final

    int getLength_impl/* $FF was: getLength-impl*/(String $this) { return $this.length(); } public static final void greet_impl/* $FF was: greet-impl*/(String $this) { String var1 = "Hello, " + $this; System.out.println(var1); } } String を結合して出力
  49. Inline Classes まとめ • コンパイル時に static method として展開される • いくつかの制約がある

    ◦ プライマリコンストラクタのプロパティは1つ ◦ init 文を持てない, class を持てない, etc. • Experimental: 変更される可能性あり
  50. isNullOrEmpty / orEmpty Collection, Map, Array に追加で導入 fun main() {

    val s: String? = null if (!s.isNullOrEmpty()) { println(s.length) } }
  51. isNullOrEmpty / orEmpty Contracts によりスマートキャストできる fun main() { val s:

    String? = null if (!s.isNullOrEmpty()) { println(s.length) } } スマートキャスト
  52. Array.copyInto 別の Array に要素をコピー可能に val source = "kotlin".toCharArray() val target

    = "java".toCharArray() source.copyInto(target, endIndex = target.size) println(target) // kotl
  53. Array.copyInto 別の Array に要素をコピー可能に val source = "kotlin".toCharArray() val target

    = "java".toCharArray() source.copyInto(target, endIndex = target.size) println(target) // kotl インデックスを適切に設定しないと ArrayIndexOutOfBoundsException
  54. associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith

    { it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc
  55. associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith

    { it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc キーに対する値を設定
  56. associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith

    { it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc
  57. ifEmpty / ifBlank Collections, Map, Array 等が空の場合の値を指定可能 fun printAllUppercase(data: List<String>)

    { val result = data .filter { it.all { c -> c.isUpperCase() } } .ifEmpty { listOf("<no uppercase>") } result.forEach { println(it) } } printAllUppercase(listOf("foo", "Bar")) // <no uppercase> printAllUppercase(listOf("FOO", "bar")) // FOO
  58. ifEmpty / ifBlank Collections, Map, Array 等が空の場合の値を指定可能 fun printAllUppercase(data: List<String>)

    { val result = data .filter { it.all { c -> c.isUpperCase() } } .ifEmpty { listOf("<no uppercase>") } result.forEach { println(it) } } printAllUppercase(listOf("foo", "Bar")) // <no uppercase> printAllUppercase(listOf("FOO", "bar")) // FOO デフォルト値
  59. ifEmpty / ifBlank Collections, Map, Array 等が空の場合の値を指定可能 fun printAllUppercase(data: List<String>)

    { val result = data .filter { it.all { c -> c.isUpperCase() } } .ifEmpty { listOf("<no uppercase>") } result.forEach { println(it) } } printAllUppercase(listOf("foo", "Bar")) // <no uppercase> printAllUppercase(listOf("FOO", "bar")) // FOO
  60. まとめ • Kotlin 1.3 の新機能についてかいつまんで説明した ◦ Coroutine ◦ Inline Classes

    ◦ Standard Libraries • Kotlin/Native, Contracts は後続の発表で • Kotlin 1.3 を使ってみよう!
  61. 参考 • What's New in Kotlin 1.3 ◦ https://kotl.in/1.3 •

    Kotlin Reference ◦ https://kotlinlang.org/docs/reference/coroutines-overview.html ◦ https://kotlinlang.org/docs/reference/inline-classes.html • GitHub ◦ https://github.com/JetBrains/kotlin