Kotlinもう一歩

 Kotlinもう一歩

Kotlinのタイプシステムとジェネリクスについて

8766b19fe1c1f8475e233c910ed6440f?s=128

kobito-kaba

August 25, 2018
Tweet

Transcript

  1. Hiroyuki Mori @moridroid Kotlinもう一歩

  2. 本書きました!

  3. goo.gl/fW2YPh

  4. Kotlinもう一歩

  5. Kotlinのタイプシステム

  6. クラスとタイプ

  7. クラス ≠ タイプ

  8. // class: String, type: String val s1: String = "string"

  9. // class: String, type: String val s1: String = "string"

    // class: String, type: String? val s2 : String? = "string"
  10. タイプとは何か

  11. ・すべての変数や式には型がある // type: String val str : String = "string"

    // type: Char if (str.isNotEmpty()) str[0] else '\n'
  12. ・型によって、変数や式のとりうる値の範囲が決まる // type: String → 文字列 val str : String =

    "string" // type: Char → 16-bit ユニコード文字 if (str.isNotEmpty()) str[0] else '\n'
  13. ・型によって、行える演算や操作が決まる // 文字列は加算できる val s = "abc" + "def" //

    整数はいろいろできる val i = 100 * (10 - 2) / (30 + 1)
  14. ・型によって、行える演算や操作が決まる // OK val str1 : String = "string" str1.hashCode()

    // nullableはいろいろできない val str2 : String? = "string" str2.hashCode() // NG
  15. だから安全!

  16. タイプとサブタイプ

  17. タイプAが期待されるすべての箇所で、 タイプBが使用可能であれば、 BはAのサブタイプ B <: A このとき、AはBのスーパータイプ

  18. val c : CharSequence = "abc" // OK fun foo(c

    : CharSequence) {} foo("abc") // OK fun bar() : CharSequence = "abc" // OK
  19. val c : CharSequence = "abc" // OK fun foo(c

    : CharSequence) {} foo("abc") // OK fun bar() : CharSequence = "abc" // OK
  20. val c : CharSequence = "abc" // OK fun foo(c

    : CharSequence) {} foo("abc") // OK fun bar() : CharSequence = "abc" // OK
  21. // Int <: Number val num1 : Number = 100

    // Double <: Number val num2 : Number = 10.0 // Long <: Number val num3 : Number = 100L
  22. Int, Long, Double, … <: Number Number Long Int Double

    Float Short Byte
  23. Int型はNumber型の範囲内 Number Int OK Long Int Double Float Short Byte

  24. Number型は、Int型の範囲内とは限らない Number Int NG Long Int Double Float Short Byte

    DoubleやLongかも?
  25. クイズ

  26. Kotlinのタイプシステムでは、 Int型はInt型の… (A) サブタイプ (B) スーパータイプ (C) どちらでもない (D) どちらでもある

  27. Kotlinのタイプシステムでは、 Int型はInt型の… (A) サブタイプ (B) スーパータイプ (C) どちらでもない (D) どちらでもある

  28. In Kotlin in Action

  29. None
  30. val intType = Int::class.createType() intType.isSubtypeOf(intType) > true intType.isSupertypeOf(intType) > true

  31. None
  32. Any

  33. // Int <: Any val any1 : Any = 100

    // Double <: Any val any2 : Any = 10.0 // String <: Any val any3 : Any = "str"
  34. // String? <: Any ……...? val any4 : Any =

    null as String?
  35. None
  36. Nothing

  37. // Why does this work? fun bar() : Int =

    TODO()
  38. // Why does this work? fun bar() : Int =

    TODO() val str1 : String = TODO() fun foo(l : List<Double>) = {} foo(TODO())
  39. public inline fun TODO(): Nothing = throw NotImplementedError() public class

    Nothing private constructor()
  40. fun nothing() : Nothing = throw Exception("nothing") val a :

    Number = nothing() val b : String = nothing() val c : List<Any> = nothing()
  41. None
  42. nullableとnon-null

  43. // String <: String? val str1 : String? = "str"

    // OK fun foo(s : String?) {} foo("abc") // OK fun bar() : String? = "abc" // OK
  44. // String <: String? val str1 : String? = "str"

    // OK // String? <: String ……..? val str2 : String = str1 // NonNull <: Nullable
  45. None
  46. まとめ

  47. None
  48. Generics

  49. fun toString(i : Int) = i.toString() fun toString(l : Long)

    = l.toString() fun toString(f : Float) = d.toString() ...
  50. fun <T> toString(t : T) = t.toString()

  51. fun toDouble(i : Int) = i.toDouble() fun toDouble(l : Long)

    = l.toDouble() fun toDouble(f : Float) = f.toDouble() ...
  52. fun <T> toDouble(t : T) = t.toDouble()

  53. 上限境界

  54. fun <T:Number> toDouble(t : T) = t.toDouble()

  55. fun <T> copyWhenGreater(list: List<T>, threshold: T) : List<String> where T

    : CharSequence, T : Comparable<T> { return list.filter { it > threshold } .map { it.toString() } }
  56. fun <T> copyWhenGreater(list: List<T>, threshold: T) : List<String> where T

    : CharSequence, T : Comparable<T> { return list.filter { it > threshold } .map { it.toString() } }
  57. 型引数とnullability

  58. fun <T> foo(t : T) = t.hashCode()

  59. fun <T> foo(t : T) = t.hashCode()

  60. fun <T> foo(t : T) = t.hashCode() fun <T :

    Any?> foo(t : T) = t?.hashCode()
  61. Type Erasure

  62. // Kotlin Code: List<String> val list : List<String> = listOf()

  63. // Kotlin Code: List<String> val list : List<String> = listOf()

    // Decompiled : List List list = CollectionsKt.emptyList();
  64. if (list is List<String>) { // You can't do this

    }
  65. 変位

  66. Int <: Number

  67. Int <: Number val number : Number = 123

  68. Int <: Number List<Int> <: List<Number>

  69. Int <: Number List<Int> <: List<Number> val nums : List<Number>

    = listOf<Int>(1, 2, 3)
  70. Int <: Number List<Int> <: List<Number> MutableList<Int> <: MutableList<Number>

  71. Int <: Number List<Int> <: List<Number> MutableList<Int> <: MutableList<Number> val

    nums : MutableList<Number> = mutableListOf<Int>(1, 2, 3)
  72. タイプAが期待されるすべての箇所で、 タイプBが使用可能であれば、 BはAのサブタイプ

  73. MutableList<Int>は、 MutableList<Number>の 代わりに使えない場合がある

  74. // もしこれが可能なら val nums : MutableList<Number> = mutableListOf<Int>(1, 2, 3)

    // これができてしまう nums.add(10.5)
  75. 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
  76. 変位 B <: A のときに、 Foo<B> と Foo<A>にどういう関係があるか

  77. invariant, covariant, contravariant  不変   共変    反変   

  78. invariant, covariant, contravariant B <: A のとき、 Foo<B> <: Foo<A>

    でもなく Foo<A> <: Foo<B> でもない
  79. class Invariant<T>(val value : T) invariant, covariant, contravariant

  80. class Invariant<T>(val value : T) val num : Invariant<Number> =

    Invariant<Int>(100)
  81. class Invariant<T>(val value : T) val num : Invariant<Number> =

    Invariant<Int>(100) val int : Invariant<Int> = Invariant<Number>(100)
  82. invariant, covariant, contravariant B <: A のとき、Foo<B> <: Foo<A>

  83. invariant, covariant, contravariant class Covariant<out T>(val value: T)

  84. class Covariant<out T>(val value: T) val num : Covariant<Number> =

    Covariant<Int>(100) invariant, covariant, contravariant
  85. class Covariant<out T>(val value: T) val num : Covariant<Number> =

    Covariant<Int>(100) val int : Covariant<Int> = Covariant<Number>(100) invariant, covariant, contravariant
  86. invariant, covariant, contravariant B <: Aのとき、Foo<A> <: Foo<B>

  87. class Contravariant<in T>(value: T) invariant, covariant, contravariant

  88. class Contravariant<in T>(value: T) val num : Contravariant<Number> = Contravariant<Int>(100)

    invariant, covariant, contravariant
  89. class Contravariant<in T>(value: T) val num : Contravariant<Number> = Contravariant<Int>(100)

    val int : Contravariant<Int> = Contravariant<Number>(10.0) invariant, covariant, contravariant
  90. 不変 共変 反変 <T> <out T> <in T> サブタイプを 引き継がない

    サブタイプを 引き継ぐ サブタイプが 逆転する
  91. inとout

  92. out

  93. class Covariant<out T> (t: T) { val value1 = t

    var value2 = t fun get() : T = value1 fun set(t: T) { value2 = t } }
  94. class Covariant<out T> (t: T) { val value = t

    fun get() : T = value }
  95. val num1 : Number = 100 val num2 : Number

    = Covariant<Int>(100).get()
  96. public interface List<out E> : Collection<E> {

  97. in

  98. class Contravariant<in T> (t: T) { val value1 = t

    var value2 = t fun get() : T = value1 fun set(t: T) { } }
  99. class Contravariant<in T> (t: T) { fun set(t: T) {

    } }
  100. val num = Contravariant<Number>(100) num.set(1234567L) num.set(10.0) num.set(123) // OK!

  101. class Contravariant<in T> (t: T) { fun set(t: T) {

    } }
  102. class Contravariant<in T> (t: T) { private var value :

    T = t private fun get() : T = value fun set(t: T) { value = t } }
  103. 不変 共変 反変 <T> <out T> <in T> サブタイプを 引き継がない

    サブタイプを 引き継ぐ サブタイプが 逆転する Tは どこでも使用可 Tは 戻り値だけ Tは 引数だけ
  104. Type Projection

  105. MutableList<Int> <: MutableList<Number>

  106. MutableList<Int> <: MutableList<Number> val nums : MutableList<out Number> = mutableListOf<Int>(1,

    2, 3)
  107. 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)
  108. class Foo<out T> val foo : Foo<in Int> class Bar<in

    T> val bar : Bar<out Int>
  109. 余談

  110. val nums : MutableList<out Number> = mutableListOf<Int>(1, 2, 3)

  111. val nums : MutableList<out Number> = mutableListOf<Int>(1, 2, 3) val

    constructor = Nothing::class.java.getDeclaredConstructor() constructor.isAccessible = true val nothing = constructor.newInstance()
  112. 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)
  113. 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]
  114. Star Projection

  115. // Java Way List<?> list;

  116. // Java Way List<?> list; // Kotlin Way val list

    : List<*>
  117. // Java Way List<?> list; // Kotlin Way val list

    : List<*> // List<out Any?>
  118. // List<out Any?> val list : List<*> = listOf(1, 2,

    3) // This is safe val foo : Any? = list[0]
  119. // MutableList<out Any?> val list : MutableList<*> = mutableListOf<Int>(1, 2,

    3) // This is not safe list.add(4.0)
  120. Star Projection と変位アノテーション

  121. out

  122. class Foo<out T : Number>(val value : T)

  123. class Foo<out T : Number>(val value : T) val foo

    : Foo<*> = Foo(1)
  124. class Foo<out T : Number>(val value : T) val foo

    : Foo<*> = Foo(1) // Foo<out Number>
  125. in

  126. class Foo<in T : Number> { fun foo(t : T)

    {} }
  127. class Foo<in T : Number> { fun foo(t : T)

    {} } val foo : Foo<*> = Foo<Number>()
  128. class Foo<in T : Number> { fun foo(t : T)

    {} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing>
  129. class Foo<in T : Number> { fun foo(t : T)

    {} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing>
  130. None
  131. class Foo<in T : Number> { fun foo(t : T)

    {} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing>
  132. class Foo<in T : Number> { fun foo(t : T)

    {} } val foo : Foo<*> = Foo<Number>() // Foo<in Nothing> foo.foo(1) // requires Nothing
  133. invariant

  134. class Foo<T : Number> { fun foo() : T =

    TODO() fun bar(t : T) {} }
  135. class Foo<T : Number> { fun foo() : T =

    TODO() fun bar(t : T) {} } val foo : Foo<*> = Foo<Int>()
  136. class Foo<T : Number> { fun foo() : T =

    TODO() fun bar(t : T) {} } val foo : Foo<*> = Foo<Int>() val n = foo.foo() // Foo<out Number>
  137. 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>
  138. まとめ

  139. 不変 共変 反変 <T> <out T> <in T> サブタイプを 引き継がない

    サブタイプを 引き継ぐ サブタイプが 逆転する Tは どこでも使用可 Tは 戻り値だけ Tは 引数だけ
  140. class Foo<in T> Foo<*> // Foo<in Nothing> class Bar<in T

    : Int> Bar<*> // Bar<in Nothing>
  141. class Foo<out T> Foo<*> // Foo<out Any?> class Bar<out T

    : Int> Bar<*> // Bar<out Int>
  142. 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
  143. Hiroyuki Mori @moridroid Thank you