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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
自作OSでスライド発表する
uyuki234
1
3.6k
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
140
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
140
ADKを使って簡単にAIエージェントを作ってみよう
k1mu21
0
290
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
380
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
620
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.7k
Webフレームワークの ベンチマークについて
yusukebe
0
190
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
1
540
エージェンティックRAGにAWSで入門しよう!
har1101
9
1.9k
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
340
act1-costs.pdf
sumedhbala
0
150
Featured
See All Featured
Building a A Zero-Code AI SEO Workflow
portentint
PRO
0
620
The Cult of Friendly URLs
andyhume
79
6.9k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Paper Plane
katiecoart
PRO
1
52k
How to build a perfect <img>
jonoalderson
1
5.8k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
590
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
380
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.9k
Abbi's Birthday
coloredviolet
3
8.4k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.5k
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
280
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.5k
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!!