Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
コードで見るKotlin 1.3
Search
Kohei Yamato
November 07, 2018
Programming
1
2.2k
コードで見るKotlin 1.3
Kohei Yamato
November 07, 2018
Tweet
Share
More Decks by Kohei Yamato
See All by Kohei Yamato
新卒一年目でサーバーサイド開発あるあるを踏み抜いてきた話 / Developers Boost 2019 A-7
daiwahome
4
1.8k
Other Decks in Programming
See All in Programming
GitHub Actionsのキャッシュと手を挙げることの大切さとそれに必要なこと
satoshi256kbyte
5
430
タクシーアプリ『GO』のリアルタイムデータ分析基盤における機械学習サービスの活用
mot_techtalk
4
1.4k
TypeScriptでライブラリとの依存を限定的にする方法
tutinoko
2
670
Amazon Bedrock Agentsを用いてアプリ開発してみた!
har1101
0
330
.NET のための通信フレームワーク MagicOnion 入門 / Introduction to MagicOnion
mayuki
1
1.5k
Realtime API 入門
riofujimon
0
150
[Do iOS '24] Ship your app on a Friday...and enjoy your weekend!
polpielladev
0
100
AI時代におけるSRE、 あるいはエンジニアの生存戦略
pyama86
6
1.1k
Creating a Free Video Ad Network on the Edge
mizoguchicoji
0
120
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
リアーキテクチャxDDD 1年間の取り組みと進化
hsawaji
1
220
役立つログに取り組もう
irof
28
9.6k
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
Scaling GitHub
holman
458
140k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
Git: the NoSQL Database
bkeepers
PRO
427
64k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
1.9k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Practical Orchestrator
shlominoach
186
10k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
16
2.1k
GraphQLの誤解/rethinking-graphql
sonatard
67
10k
The World Runs on Bad Software
bkeepers
PRO
65
11k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
27
4.3k
Thoughts on Productivity
jonyablonski
67
4.3k
Transcript
コードで見る Kotlin 1.3 どこでもKotlin #6 エムスリー株式会社 大和康平
自己紹介 • 大和 康平 (24) • エムスリー 2018年4月入社 • 仕事の担当:
サーバーサイド • 趣味: モータースポーツ観戦
発表の概要 • 基本的にはこちらの内容 ◦ What's New in Kotlin 1.3 (https://kotl.in/1.3)
• この中から3つをピックアップして紹介 ◦ Coroutines (ごく一部) ◦ Inline Classes ◦ Standard Libraries
Kotlin 1.3 リリース
Kotlin 1.3 事始め コマンドラインの場合: Gradleの場合: $ brew install kotlin plugins
{ id 'org.jetbrains.kotlin.jvm' version '1.3.0' }
Coroutines
Coroutines • 基本は軽量なスレッド • CoroutineScope 中の coroutine builder により起動する ◦
launch ◦ runBlocking ◦ async
Coroutines dependencies { implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.0' } coroutine の実行に必要
GrobalScope fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")
Thread.sleep(2000L) }
GrobalScope fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")
Thread.sleep(2000L) } GlobalScope の coroutine
GrobalScope • CoroutineScope の一種 • ライフタイム: アプリケーション終了時まで
launch coroutine builder • 現在のスレッドをブロックせずに、新しい coroutine を起動 する • Coroutine
への参照を Job として返す (後述)
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) }
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } メインスレッドをブロックしない が1000ms停止
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } 先に実行される
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } => Hello, World!
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") Thread.sleep(2000L) } => Hello, World! 2000ms停止することで待 ち合わせ
launch coroutine builder fun main() { GlobalScope.launch { delay(1000L) println("World!")
} println("Hello,") } => Hello, 実行される前に終了
Job fun main() { GlobalScope.launch { delay(1000L) println("World!") } println("Hello,")
Thread.sleep(2000L) } coroutineの内容によらず 2000ms停止......
Job fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() }
Job • launch coroutine builder の返り値 • いくつかの状態を持つ ◦ New,
Active, Completing, Cancelling, Cancelled, Completed • Job#join を実行することにより、完了するまで呼び出し元 の coroutine を停止できる
Job fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() } coroutineが完了するまで待ち合わせ
Job fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() } => Hello, World!
runBlocking coroutine builder • 現在のスレッドをブロックして、新しい coroutine を起動する • コードブロックの返り値をそのまま返す
runBlocking coroutine builder fun main() { val job = GlobalScope.launch
{ delay(1000L) println("World!") } println("Hello,") job.join() }
runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")
} println("Hello,") }
runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")
} println("Hello,") } 完了するまでメインスレッドをブ ロック
runBlocking coroutine builder fun main() { runBlocking { delay(1000L) println("World!")
} println("Hello,") } => World! (約1秒後) Hello,
CoroutineScope fun main() { val job = GlobalScope.launch { delay(1000L)
println("World!") } println("Hello,") job.join() }
CoroutineScope fun main() = runBlocking { val job = GlobalScope.launch
{ delay(1000L) println("World!") } println("Hello,") job.join() }
CoroutineScope fun main() = runBlocking { launch { delay(1000L) println("World!")
} println("Hello,") }
CoroutineScope fun main() = runBlocking { // this: CoroutineScope launch
{ delay(1000L) println("World!") } println("Hello,") }
CoroutineScope • 全ての coroutine builder は、そのコードブロックのスコープ に CroutineScope のインスタンスを追加する •
外のコルーチンは、スコープ中で起動されたコルーチンが全 て終了するまで完了しない
CoroutineScope fun main() = runBlocking { launch { delay(1000L) println("World!")
} println("Hello,") } => Hello, World! coroutine が完了するまで アプリケーションは終了しない
async coroutine builder • 現在のスレッドをブロックせずに、新しい coroutine を起動 する ◦ launch
と同じ • 将来の実行結果を Deferred として返す
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) } async による coroutine
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) } coroutine の完了まで待つ
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L) 10 } println(x.await()) } => 10 (約1秒後)
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) }
async coroutine builder fun main() = runBlocking { val x
= async { delay(1000L); 10 } val y = async { delay(2000L); 20 } println(x.await() + y.await()) } 最大2000ms停止
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秒後)
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
Coroutines まとめ • Coroutine builder を使用して作成する ◦ launch ◦ runBlocking
◦ async • 階層構造を持たせて実行するとよい
Inline Classes [experimental]
Inline Classes • コンパイル時にオーバーヘッドが少ない形で展開されるクラ ス • プライマリコンストラクタで、プロパティを1つのみ宣言できる
プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val
securePassword = Password("Don't try this in production") println(securePassword.value) }
プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val
securePassword = Password("Don't try this in production") println(securePassword.value) } プロパティを1つ持つ Inline Class
プライマリコンストラクタのみ inline class Password(val value: String) fun main() { val
securePassword = Password("Don't try this in production") println(securePassword.value) } 通常の Class として利用できる
プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword
= Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } Java に逆コンパイルした main 関数
プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword
= Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } プロパティの型が返る
プライマリコンストラクタのみ (decompiled) public static final void main() { String securePassword
= Password.constructor-impl("Don't try this in production"); System.out.println(securePassword); } static method として実行される
プライマリコンストラクタのみ (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
プライマリコンストラクタのみ (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 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) }
プロパティ&メソッド 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つのみ
プロパティ&メソッド 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) }
プロパティ&メソッド 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) } それぞれ単純な処理
プロパティ&メソッド (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); }
プロパティ&メソッド (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 を返す
プロパティ&メソッド (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 が呼ばれる
プロパティ&メソッド (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); } }
プロパティ&メソッド (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() を呼び出すだけ
プロパティ&メソッド (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 を結合して出力
Inline Classes まとめ • コンパイル時に static method として展開される • いくつかの制約がある
◦ プライマリコンストラクタのプロパティは1つ ◦ init 文を持てない, class を持てない, etc. • Experimental: 変更される可能性あり
Standard Libraries
Random マルチプラットフォームで利用可能な Random が追加 val number = Random.nextInt(42) println(number) //
0 <= number < 42
Random マルチプラットフォームで利用可能な Random が追加 val number = Random(111).nextInt(42) println(number) //
0 <= number < 42 seed も指定可能
Random IntRange 等の拡張関数も追加されている val number = (0..41).random() println(number) // 0
<= number <= 41
isNullOrEmpty / orEmpty Collection, Map, Array に追加で導入 fun main() {
val s: String? = null if (!s.isNullOrEmpty()) { println(s.length) } }
isNullOrEmpty / orEmpty Contracts によりスマートキャストできる fun main() { val s:
String? = null if (!s.isNullOrEmpty()) { println(s.length) } } スマートキャスト
isNullOrEmpty / orEmpty Contracts によりスマートキャストできる @kotlin.internal.InlineOnly public inline fun CharSequence?.isNullOrEmpty():
Boolean { contract { return(false) implies (this@isNullOrEmpty != null) } return random(Random) }
Array.copyInto 別の Array に要素をコピー可能に val source = "kotlin".toCharArray() val target
= "java".toCharArray() source.copyInto(target, endIndex = target.size) println(target) // kotl
Array.copyInto 別の Array に要素をコピー可能に val source = "kotlin".toCharArray() val target
= "java".toCharArray() source.copyInto(target, endIndex = target.size) println(target) // kotl インデックスを適切に設定しないと ArrayIndexOutOfBoundsException
associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith
{ it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc
associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith
{ it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc キーに対する値を設定
associateWith キーのリストから値を関連付けてマップを作成可能 val keys = 'a'..'c' val map = keys.associateWith
{ it.toString().repeat(5).capitalize() } map.forEach { println(it) } // a=Aaaaa // b=Bbbbb // c=Ccccc
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
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 デフォルト値
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
その他 @SinceKotlin(“1.3”) で検索することで見つけられる @SinceKotlin("1.3") @kotlin.internal.InlineOnly public inline fun IntRange.random(): Int
{ return random(Random) }
まとめ
まとめ • Kotlin 1.3 の新機能についてかいつまんで説明した ◦ Coroutine ◦ Inline Classes
◦ Standard Libraries • Kotlin/Native, Contracts は後続の発表で • Kotlin 1.3 を使ってみよう!
参考 • 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
Have a nice Kotlin!!