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もう一歩
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
kobito-kaba
August 25, 2018
Programming
8
17k
Kotlinもう一歩
Kotlinのタイプシステムとジェネリクスについて
kobito-kaba
August 25, 2018
Tweet
Share
More Decks by kobito-kaba
See All by kobito-kaba
新規プロジェクトでやってよかったことまとめ
kobitokaba
1
880
Youtube like BottomNavigation
kobitokaba
0
250
Modularizing and Refactoring Android App with Clean Architecture
kobitokaba
0
290
Slice Your App
kobitokaba
2
1.2k
Inside Jetpack
kobitokaba
2
160
Generating and Transforming Kotlin code
kobitokaba
0
130
Conference Tourism
kobitokaba
0
280
Inside Jetpack Architecture Components
kobitokaba
0
240
Inside LifecycleObserver
kobitokaba
0
130
Other Decks in Programming
See All in Programming
CDIの誤解しがちな仕様とその対処TIPS
futokiyo
0
160
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
370
ご飯食べながらエージェントが開発できる。そう、Agentic Engineeringならね。
yokomachi
1
280
Head of Engineeringが現場で回した生産性向上施策 2025→2026
gessy0129
0
210
PJのドキュメントを全部Git管理にしたら、一番喜んだのはAIだった
nanaism
0
230
Railsの気持ちを考えながらコントローラとビューを整頓する/tidying-rails-controllers-and-views-as-rails-think
moro
4
370
2026年は Rust 置き換えが流行る! / 20260220-niigata-5min-tech
girigiribauer
0
220
Rubyと楽しいをつくる / Creating joy with Ruby
chobishiba
0
200
AHC061解説
shun_pi
0
300
「やめとこ」がなくなった — 1月にZennを始めて22本書いた AI共創開発のリアル
atani14
0
340
CSC307 Lecture 11
javiergs
PRO
0
580
2026/02/04 AIキャラクター人格の実装論 口 調の模倣から、コンテキスト制御による 『思想』と『行動』の創発へ
sr2mg4
0
670
Featured
See All Featured
Paper Plane (Part 1)
katiecoart
PRO
0
5k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
270
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
2
480
Discover your Explorer Soul
emna__ayadi
2
1.1k
A better future with KSS
kneath
240
18k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
3.4k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
93
Avoiding the “Bad Training, Faster” Trap in the Age of AI
tmiket
0
96
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
220
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
60
42k
The untapped power of vector embeddings
frankvandijk
2
1.6k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.1k
Transcript
Hiroyuki Mori @moridroid Kotlinもう一歩
本書きました!
goo.gl/fW2YPh
Kotlinもう一歩
Kotlinのタイプシステム
クラスとタイプ
クラス ≠ タイプ
// class: String, type: String val s1: String = "string"
// class: String, type: String val s1: String = "string"
// class: String, type: String? val s2 : String? = "string"
タイプとは何か
・すべての変数や式には型がある // type: String val str : String = "string"
// type: Char if (str.isNotEmpty()) str[0] else '\n'
・型によって、変数や式のとりうる値の範囲が決まる // type: String → 文字列 val str : String =
"string" // type: Char → 16-bit ユニコード文字 if (str.isNotEmpty()) str[0] else '\n'
・型によって、行える演算や操作が決まる // 文字列は加算できる val s = "abc" + "def" //
整数はいろいろできる val i = 100 * (10 - 2) / (30 + 1)
・型によって、行える演算や操作が決まる // OK val str1 : String = "string" str1.hashCode()
// nullableはいろいろできない val str2 : String? = "string" str2.hashCode() // NG
だから安全!
タイプとサブタイプ
タイプAが期待されるすべての箇所で、 タイプBが使用可能であれば、 BはAのサブタイプ B <: A このとき、AはBのスーパータイプ
val c : CharSequence = "abc" // OK fun foo(c
: CharSequence) {} foo("abc") // OK fun bar() : CharSequence = "abc" // OK
val c : CharSequence = "abc" // OK fun foo(c
: CharSequence) {} foo("abc") // OK fun bar() : CharSequence = "abc" // OK
val c : CharSequence = "abc" // OK fun foo(c
: CharSequence) {} foo("abc") // OK fun bar() : CharSequence = "abc" // OK
// Int <: Number val num1 : Number = 100
// Double <: Number val num2 : Number = 10.0 // Long <: Number val num3 : Number = 100L
Int, Long, Double, … <: Number Number Long Int Double
Float Short Byte
Int型はNumber型の範囲内 Number Int OK Long Int Double Float Short Byte
Number型は、Int型の範囲内とは限らない Number Int NG Long Int Double Float Short Byte
DoubleやLongかも?
クイズ
Kotlinのタイプシステムでは、 Int型はInt型の… (A) サブタイプ (B) スーパータイプ (C) どちらでもない (D) どちらでもある
Kotlinのタイプシステムでは、 Int型はInt型の… (A) サブタイプ (B) スーパータイプ (C) どちらでもない (D) どちらでもある
In Kotlin in Action
None
val intType = Int::class.createType() intType.isSubtypeOf(intType) > true intType.isSupertypeOf(intType) > true
None
Any
// Int <: Any val any1 : Any = 100
// Double <: Any val any2 : Any = 10.0 // String <: Any val any3 : Any = "str"
// String? <: Any ……...? val any4 : Any =
null as String?
None
Nothing
// Why does this work? fun bar() : Int =
TODO()
// Why does this work? fun bar() : Int =
TODO() val str1 : String = TODO() fun foo(l : List<Double>) = {} foo(TODO())
public inline fun TODO(): Nothing = throw NotImplementedError() public class
Nothing private constructor()
fun nothing() : Nothing = throw Exception("nothing") val a :
Number = nothing() val b : String = nothing() val c : List<Any> = nothing()
None
nullableとnon-null
// String <: String? val str1 : String? = "str"
// OK fun foo(s : String?) {} foo("abc") // OK fun bar() : String? = "abc" // OK
// String <: String? val str1 : String? = "str"
// OK // String? <: String ……..? val str2 : String = str1 // NonNull <: Nullable
None
まとめ
None
Generics
fun toString(i : Int) = i.toString() fun toString(l : Long)
= l.toString() fun toString(f : Float) = d.toString() ...
fun <T> toString(t : T) = t.toString()
fun toDouble(i : Int) = i.toDouble() fun toDouble(l : Long)
= l.toDouble() fun toDouble(f : Float) = f.toDouble() ...
fun <T> toDouble(t : T) = t.toDouble()
上限境界
fun <T:Number> toDouble(t : T) = t.toDouble()
fun <T> copyWhenGreater(list: List<T>, threshold: T) : List<String> where T
: CharSequence, T : Comparable<T> { return list.filter { it > threshold } .map { it.toString() } }
fun <T> copyWhenGreater(list: List<T>, threshold: T) : List<String> where T
: CharSequence, T : Comparable<T> { return list.filter { it > threshold } .map { it.toString() } }
型引数とnullability
fun <T> foo(t : T) = t.hashCode()
fun <T> foo(t : T) = t.hashCode()
fun <T> foo(t : T) = t.hashCode() fun <T :
Any?> foo(t : T) = t?.hashCode()
Type Erasure
// Kotlin Code: List<String> val list : List<String> = listOf()
// Kotlin Code: List<String> val list : List<String> = listOf()
// Decompiled : List List list = CollectionsKt.emptyList();
if (list is List<String>) { // You can't do this
}
変位
Int <: Number
Int <: Number val number : Number = 123
Int <: Number List<Int> <: List<Number>
Int <: Number List<Int> <: List<Number> val nums : List<Number>
= listOf<Int>(1, 2, 3)
Int <: Number List<Int> <: List<Number> MutableList<Int> <: MutableList<Number>
Int <: Number List<Int> <: List<Number> MutableList<Int> <: MutableList<Number> val
nums : MutableList<Number> = mutableListOf<Int>(1, 2, 3)
タイプAが期待されるすべての箇所で、 タイプBが使用可能であれば、 BはAのサブタイプ
MutableList<Int>は、 MutableList<Number>の 代わりに使えない場合がある
// もしこれが可能なら val nums : MutableList<Number> = mutableListOf<Int>(1, 2, 3)
// これができてしまう nums.add(10.5)
val nums = mutableListOf<Number>(1, 2, 3) val ints = mutableListOf<Int>(1,
2, 3) val num1 : Number = nums[0] // OK val num2 : Number = ints[0] // OK nums.add(10.0) // OK ints.add(10.0) // NG
変位 B <: A のときに、 Foo<B> と Foo<A>にどういう関係があるか
invariant, covariant, contravariant 不変 共変 反変
invariant, covariant, contravariant B <: A のとき、 Foo<B> <: Foo<A>
でもなく Foo<A> <: Foo<B> でもない
class Invariant<T>(val value : T) invariant, covariant, contravariant
class Invariant<T>(val value : T) val num : Invariant<Number> =
Invariant<Int>(100)
class Invariant<T>(val value : T) val num : Invariant<Number> =
Invariant<Int>(100) val int : Invariant<Int> = Invariant<Number>(100)
invariant, covariant, contravariant B <: A のとき、Foo<B> <: Foo<A>
invariant, covariant, contravariant class Covariant<out T>(val value: T)
class Covariant<out T>(val value: T) val num : Covariant<Number> =
Covariant<Int>(100) invariant, covariant, contravariant
class Covariant<out T>(val value: T) val num : Covariant<Number> =
Covariant<Int>(100) val int : Covariant<Int> = Covariant<Number>(100) invariant, covariant, contravariant
invariant, covariant, contravariant B <: Aのとき、Foo<A> <: Foo<B>
class Contravariant<in T>(value: T) invariant, covariant, contravariant
class Contravariant<in T>(value: T) val num : Contravariant<Number> = Contravariant<Int>(100)
invariant, covariant, contravariant
class Contravariant<in T>(value: T) val num : Contravariant<Number> = Contravariant<Int>(100)
val int : Contravariant<Int> = Contravariant<Number>(10.0) invariant, covariant, contravariant
不変 共変 反変 <T> <out T> <in T> サブタイプを 引き継がない
サブタイプを 引き継ぐ サブタイプが 逆転する
inとout
out
class Covariant<out T> (t: T) { val value1 = t
var value2 = t fun get() : T = value1 fun set(t: T) { value2 = t } }
class Covariant<out T> (t: T) { val value = t
fun get() : T = value }
val num1 : Number = 100 val num2 : Number
= Covariant<Int>(100).get()
public interface List<out E> : Collection<E> {
in
class Contravariant<in T> (t: T) { val value1 = t
var value2 = t fun get() : T = value1 fun set(t: T) { } }
class Contravariant<in T> (t: T) { fun set(t: T) {
} }
val num = Contravariant<Number>(100) num.set(1234567L) num.set(10.0) num.set(123) // OK!
class Contravariant<in T> (t: T) { fun set(t: T) {
} }
class Contravariant<in T> (t: T) { private var value :
T = t private fun get() : T = value fun set(t: T) { value = t } }
不変 共変 反変 <T> <out T> <in T> サブタイプを 引き継がない
サブタイプを 引き継ぐ サブタイプが 逆転する Tは どこでも使用可 Tは 戻り値だけ Tは 引数だけ
Type Projection
MutableList<Int> <: MutableList<Number>
MutableList<Int> <: MutableList<Number> val nums : MutableList<out Number> = mutableListOf<Int>(1,
2, 3)
MutableList<Int> <: MutableList<Number> val nums : MutableList<out Number> = mutableListOf<Int>(1,
2, 3) val nums : MutableList<in Int> = mutableListOf<Number>(1.0, 2.0, 3.0)
class Foo<out T> val foo : Foo<in Int> class Bar<in
T> val bar : Bar<out Int>
余談
val nums : MutableList<out Number> = mutableListOf<Int>(1, 2, 3)
val nums : MutableList<out Number> = mutableListOf<Int>(1, 2, 3) val
constructor = Nothing::class.java.getDeclaredConstructor() constructor.isAccessible = true val nothing = constructor.newInstance()
val nums : MutableList<out Number> = mutableListOf<Int>(1, 2, 3) val
constructor = Nothing::class.java.getDeclaredConstructor() constructor.isAccessible = true val nothing = constructor.newInstance() nums.add(nothing)
val nums : MutableList<out Number> = mutableListOf<Int>(1, 2, 3) val
constructor = Nothing::class.java.getDeclaredConstructor() constructor.isAccessible = true val nothing = constructor.newInstance() nums.add(nothing) print(nums) > [1, 2, 3, java.lang.Void@5e9d7b78]
Star Projection
// Java Way List<?> list;
// Java Way List<?> list; // Kotlin Way val list
: List<*>
// Java Way List<?> list; // Kotlin Way val list
: List<*> // List<out Any?>
// List<out Any?> val list : List<*> = listOf(1, 2,
3) // This is safe val foo : Any? = list[0]
// MutableList<out Any?> val list : MutableList<*> = mutableListOf<Int>(1, 2,
3) // This is not safe list.add(4.0)
Star Projection と変位アノテーション
out
class Foo<out T : Number>(val value : T)
class Foo<out T : Number>(val value : T) val foo
: Foo<*> = Foo(1)
class Foo<out T : Number>(val value : T) val foo
: Foo<*> = Foo(1) // Foo<out Number>
in
class Foo<in T : Number> { fun foo(t : T)
{} }
class Foo<in T : Number> { fun foo(t : T)
{} } val foo : Foo<*> = Foo<Number>()
class Foo<in T : Number> { fun foo(t : T)
{} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing>
class Foo<in T : Number> { fun foo(t : T)
{} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing>
None
class Foo<in T : Number> { fun foo(t : T)
{} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing>
class Foo<in T : Number> { fun foo(t : T)
{} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing> foo.foo(1) // requires Nothing
invariant
class Foo<T : Number> { fun foo() : T =
TODO() fun bar(t : T) {} }
class Foo<T : Number> { fun foo() : T =
TODO() fun bar(t : T) {} } val foo : Foo<*> = Foo<Int>()
class Foo<T : Number> { fun foo() : T =
TODO() fun bar(t : T) {} } val foo : Foo<*> = Foo<Int>() val n = foo.foo() // Foo<out Number>
class Foo<T : Number> { fun foo() : T =
TODO() fun bar(t : T) {} } val foo : Foo<*> = Foo<Int>() val n = foo.foo() // Foo<out Number> foo.bar(n) // Foo<in Nothing>
まとめ
不変 共変 反変 <T> <out T> <in T> サブタイプを 引き継がない
サブタイプを 引き継ぐ サブタイプが 逆転する Tは どこでも使用可 Tは 戻り値だけ Tは 引数だけ
class Foo<in T> Foo<*> // Foo<in Nothing> class Bar<in T
: Int> Bar<*> // Bar<in Nothing>
class Foo<out T> Foo<*> // Foo<out Any?> class Bar<out T
: Int> Bar<*> // Bar<out Int>
class Foo<T> Foo<*> // Foo<out Any?> : out position //
Foo<in Nothing> : in position class Bar<T : Int> Bar<*> // Bar<out Int> : out position // Bar<in Nothing> : in position
Hiroyuki Mori @moridroid Thank you