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
2.5k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
コードで見るKotlin 1.3
Kohei Yamato
November 07, 2018
More Decks by Kohei Yamato
See All by Kohei Yamato
新卒一年目でサーバーサイド開発あるあるを踏み抜いてきた話 / Developers Boost 2019 A-7
daiwahome
4
2k
Other Decks in Programming
See All in Programming
そこに3びきプロダクトがいるじゃろう——生成AI時代における“価値が届かない理由”の構造
kosuket
0
560
運用ダッシュボードの設計を誰も教えてくれないのだけどみなさんどうしてるんですか? - チームに監視するという文化を根付かせるための第一歩を踏みたい -
satoshi256kbyte
1
140
ドリフトを絶対に許さない(?)CDK運用 / CDK Ops with Zero Tolerance for Drifts (?)
akihisaikeda
1
220
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
19k
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
280
初めての模倣学習とVLA
natsutan
0
170
Jindong: Introducing Declarative Haptics in Compose Multiplatform
l2hyunwoo
0
130
進化を続けるGo toolsの現在地 / The Current State of Ever-Evolving Go Tools
hond0413
0
250
Cloudflare is Agents
chimame
0
180
Gmail/Google DriveをトリガーにAIエージェントを動かそう! / Run AI agents with Gmail/Google Drive as triggers!
har1101
2
400
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
270
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
360
Featured
See All Featured
Prompt Engineering for Job Search
mfonobong
0
410
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.1k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
66
57k
Site-Speed That Sticks
csswizardry
13
1.5k
Between Models and Reality
mayunak
4
400
The Curious Case for Waylosing
cassininazir
1
470
Test your architecture with Archunit
thirion
2
2.4k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
290
Building Applications with DynamoDB
mza
96
7.2k
From Legacy to Launchpad: Building Startup-Ready Communities
dugsong
0
300
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.5k
Context Engineering - Making Every Token Count
addyosmani
9
1.1k
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!!