Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Fest 2019: Kotlin型実践入門

Sato Shun
August 24, 2019

Kotlin Fest 2019: Kotlin型実践入門

KotlinではJavaにはない様々な型に関する機能が追加されたので、それらの解説

- Smart Casts
- Any、Unit、Nothing
- ジェネリクス
- Sealed class
- 関数型

Sato Shun

August 24, 2019
Tweet

More Decks by Sato Shun

Other Decks in Technology

Transcript

  1. Kotlin Fest 2019 ࠤ౻ ൏ / Sato Shun Twitter: @stsn_jp

    GitHub: satoshun Kotlinܕ࣮ફೖ໳
  2. Smart Casts • ifࣜɺwhenࣜɺisɺasͳͲͷ࣮ߦޙʹɺ໌ࣔతʹܕΩϟετ ͠ͳͯ͘΋ɺܕΛਪ࿦ͯ͘͠ΕΔ • flow-sensitive typing (flow typing)ͱݺ͹ΕΔܕγεςϜ

    • ৑௕ͳܕΩϟετΛܰݮ͢Δ • ಈతܕ෇͚ݴޠͷμοΫλΠϐϯάͷΑ͏ͳॻ͖৺஍ • https://en.wikipedia.org/wiki/Flow-sensitive_typing
  3. if (obj is String) { a print((obj as String).length) }

    a if (obj !is String) return print((obj as String).length) when (obj) { aa is Int -> print((obj as Int) + 1) is String -> print((obj as String).length + 1) is IntArray -> print((obj as IntArray).sum() + 1) } a
  4. if (obj is String) { a print(obj.length) } a if

    (obj !is String) return print((obj as String).length) when (obj) { aa is Int -> print((obj as Int) + 1) is String -> print((obj as String).length + 1) is IntArray -> print((obj as IntArray).sum() + 1) } a
  5. if (obj is String) { a print(obj.length) } a if

    (obj !is String) return print(obj.length) when (obj) { aa is Int -> print((obj as Int) + 1) is String -> print((obj as String).length + 1) is IntArray -> print((obj as IntArray).sum() + 1) } a
  6. if (obj is String) { a print(obj.length) } a if

    (obj !is String) return print(obj.length) when (obj) { a is Int -> print(obj + 1) is String -> print(obj.length + 1) is IntArray -> print(obj.sum() + 1) } a
  7. if (hoge() && obj is Int) { a (obj as

    Int).toLong() } a if (obj is String && obj is Int) { a (obj as String).length (obj as Int).toLong() } a
  8. if (hoge() && obj is Int) { a obj.toLong() }

    a if (obj is String && obj is Int) { a (obj as String).length (obj as Int).toLong() } a
  9. if (hoge() && obj is Int) { a obj.toLong() }

    a if (obj is String && obj is Int) { a obj.length obj.toLong() } a
  10. class Hoge { a private var obj: Any = "a"

    fun test() { a if (obj is String) { a print((obj as String).length) } a } a } a
  11. class Hoge { a private var obj: Any = "a"

    fun test() { a if (obj is String) { a print(obj.length) } a } a } a
  12. class Hoge { a private var obj: Any = "a"

    fun test() { a if (obj is String) { a print(obj.length) } a } a } a ❌
  13. class Hoge { a private var obj: Any = "a"

    fun test() { a val obj = obj if (obj is String) { a print(obj.length) } a } a } a
  14. class Hoge { a private var obj: Any = "a"

    fun test() { a obj.let { a if (it is String) { a print(it.length) } a } a } a } a
  15. public inline fun <T> Collection<T>?.isNullOrEmpty(): Boolean { a contract {

    a returns(false) implies (this@isNullOrEmpty != null) } a return this == null || this.isEmpty() } a
  16. public inline fun <T> Collection<T>?.isNullOrEmpty(): Boolean { a contract {

    a returns(false) implies (this@isNullOrEmpty != null) } a return this == null || this.isEmpty() } a
  17. public inline fun <T> Collection<T>?.isNullOrEmpty(): Boolean { a contract {

    a returns(false) implies (this@isNullOrEmpty != null) } a return this == null || this.isEmpty() } a
  18. public inline fun <T> Collection<T>?.isNullOrEmpty(): Boolean { a contract {

    a returns(false) implies (this@isNullOrEmpty != null) } a return this == null || this.isEmpty() } a
  19. fun assertTrue(actual: Boolean, message: String? = null) { a contract

    { returns() implies actual } a return asserter.assertTrue(message ?: "Expected value to be true.", actual) } a
  20. fun assertTrue(actual: Boolean, message: String? = null) { a contract

    { returns() implies actual } a return asserter.assertTrue(message ?: "Expected value to be true.", actual) } a
  21. fun assertTrue(actual: Boolean, message: String? = null) { a contract

    { returns() implies actual } a return asserter.assertTrue(message ?: "Expected value to be true.", actual) } a assertTrue(obj != null) print(obj!!.length)
  22. fun assertTrue(actual: Boolean, message: String? = null) { a contract

    { returns() implies actual } a return asserter.assertTrue(message ?: "Expected value to be true.", actual) } a assertTrue(obj != null) print(obj.length)
  23. fun assertFalse(actual: Boolean, message: String? = null) { contract {

    returns() implies (!actual) } return asserter.assertTrue(message ?: "Expected value to be false.", !actual) } assertFalse(obj == null) print(obj.length)
  24. fun assertFalse(actual: Boolean, message: String? = null) { contract {

    returns() implies (!actual) } return asserter.assertTrue(message ?: "Expected value to be false.", !actual) } assertFalse(obj == null) print(obj.length)
  25. public inline fun <R> run(block: () -> R): R {

    a contract { a callsInPlace(block, InvocationKind.EXACTLY_ONCE) } a return block() } a
  26. public inline fun <R> run(block: () -> R): R {

    a contract { a callsInPlace(block, InvocationKind.EXACTLY_ONCE) } a return block() } a
  27. public inline fun <R> run(block: () -> R): R {

    a contract { a callsInPlace(block, InvocationKind.EXACTLY_ONCE) } a return block() } a var s: String? = null a run { a s = "" a } a println(s!!) a
  28. public inline fun <R> run(block: () -> R): R {

    a contract { a callsInPlace(block, InvocationKind.EXACTLY_ONCE) } a return block() } a val s: String a run { a s = "" a } a println(s) a
  29. fun checkObj(obj: Any?): Boolean { a return obj != null

    } a if (checkObj(obj)) { a obj!!.javaClass } a
  30. fun checkObj(obj: Any?): Boolean { a contract { a returns(true)

    implies (obj != null) } a return obj != null } a if (checkObj(obj)) { a obj!!.javaClass } a
  31. fun checkObj(obj: Any?): Boolean { a contract { a returns(true)

    implies (obj != null) } a return obj != null } a if (checkObj(obj)) { a obj!!.javaClass } a
  32. fun checkObj(obj: Any?): Boolean { a contract { a returns(true)

    implies (obj != null) } a return obj != null } a if (checkObj(obj)) { a obj!!.javaClass } a
  33. fun checkObj(obj: Any?): Boolean { a contract { a returns(true)

    implies (obj != null) } a return obj != null } a if (checkObj(obj)) { a obj.javaClass } a
  34. @UseExperimental(ExperimentalContracts::class) fun checkObj(obj: Any?): Boolean { a contract { a

    returns(true) implies (obj != null) } a return obj != null } a if (checkObj(obj)) { a obj.javaClass } a
  35. fun getName(): String { a return "name" } a fun

    fail() { a throw RuntimeException() } a
  36. fun getName(): String { a return "name" } a fun

    fail() { a throw RuntimeException() } a val name = if (isFriend()) { a getName() } a else { a fail() } a
  37. fun getName(): String { a return "name" } a fun

    fail() { a throw RuntimeException() } a val name: Any = if (isFriend()) { a getName() } a else { a fail() } a
  38. fun getName(): String { a return "name" } a fun

    fail() { a throw RuntimeException() } a val name: Any = if (isFriend()) { a getName() } a else { a fail() } a
  39. fun getName(): String { a return "name" } a fun

    fail() { a throw RuntimeException() } a val name: Any = if (isFriend()) { a getName() } a else { a fail() } a println((name as String).length)
  40. fun getName(): String { a return "name" } a fun

    fail(): Nothing { a throw RuntimeException() } a val name: Any = if (isFriend()) { a getName() } a else { a fail() } a println((name as String).length)
  41. fun getName(): String { a return "name" } a fun

    fail(): Nothing { a throw RuntimeException() } a val name: Any = if (isFriend()) { a getName() } a else { a fail() } a println((name as String).length)
  42. fun getName(): String { a return "name" } a fun

    fail(): Nothing { a throw RuntimeException() } a val name: Any = if (isFriend()) { a getName() } a else { a fail() } a println((name as String).length)
  43. fun getName(): String { a return "name" } a fun

    fail(): Nothing { a throw RuntimeException() } a val name: String = if (isFriend()) { a getName() } a else { a fail() } a println((name as String).length)
  44. fun getName(): String { a return "name" } a fun

    fail(): Nothing { a throw RuntimeException() } a val name: String = if (isFriend()) { a getName() } a else { a fail() } a println(name.length)
  45. fun getName(): String { a return "name" } a fun

    fail(): Nothing { a throw RuntimeException() } a val name = if (isFriend()) { a getName() } a else { a fail() } a println(name.length)
  46. fun test(any: Any): String { a when (any) { a

    is Int -> return "int" else -> fail() } a return "error" } a
  47. fun test(any: Any): String { a when (any) { a

    is Int -> return "int" else -> fail() } a return "error" } a NothingܕͳͷͰɺ͜ͷݺͼग़͠͸ਖ਼ৗʹऴྃ͠ͳ͍ ͜ͷelse͸ඞࣦͣഊ͢Δ
  48. fun test(any: Any): String { a when (any) { a

    is Int -> return "int" else -> fail() } a } a
  49. // ඪ४ؔ਺ public inline fun TODO(): Nothing = throw NotImplementedError()

    // KotlinTest fun fail(msg: String): Nothing = throw Failures.failure(msg)
  50. // Kotlin/kotlinx.collections.immutable internal companion object { internal val EMPTY =

    TrieNode<Nothing>(0, emptyArray()) } // airbnb/MvRx object Uninitialized : Async<Nothing>(complete = false, shouldLoad = true), Incomplete
  51. // kotlintest/kotlintest interface Show<in A> { a fun supports(a: Any?):

    Boolean fun show(a: A): String } a object NullShow : Show<Nothing?> { a override fun supports(a: Any?): Boolean = a == null override fun show(a: Nothing?): String = "<null>" } a
  52. ෼ࢄΞϊςʔγϣϯ • out - ڞม: covariance • in - ൓ม:

    contravariance • ࢦఆͳ͠: ෆม: invariance
  53. ڞมɺ൓มɺෆม • Number <|- Intͷܧঝؔ܎͕͋Δ • A<Number> <|- A<Int>ͷ৔߹ɺA͸ڞมͰ͋Δ •

    A<Number> -|> A<Int>ͷ৔߹ɺA͸൓มͰ͋Δ • A<Number>ɺ A<Int>͕ؔ܎ͳ͍৔߹ɺA͸ෆมͰ͋Δ
  54. ڞมɺ൓มɺෆม • Number <|- Intͷܧঝؔ܎͕͋Δ • A<Number> <|- A<Int>ͷ৔߹ɺA͸ڞมͰ͋Δ •

    A<Number> -|> A<Int>ͷ৔߹ɺA͸൓มͰ͋Δ • A<Number>ɺ A<Int>͕ؔ܎ͳ͍৔߹ɺA͸ෆมͰ͋Δ
  55. // ڞม val a: A<Int> = A<Int>() a val b:

    A<Number> = a // ൓ม val a: A<Number> = A<Number>() a val b: A<Int> = a
  56. // ڞม val a: A<Int> = A<Int>() a val b:

    A<Number> = a // ൓ม val a: A<Number> = A<Number>() a val b: A<Int> = a // ෆม val a: A<Int> = A<Int>() a
  57. interface Mapper<T> { a fun map(s: String): T } a

    class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a
  58. interface Mapper<T> { a fun map(s: String): T } a

    class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a
  59. interface Mapper<T> { a fun map(s: String): T } a

    class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a val mapper = IntMapper() hoge(mapper)
  60. interface Mapper<T> { a fun map(s: String): T } a

    class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a val mapper = IntMapper() hoge(mapper) ❌
  61. interface Mapper<T> { a fun map(s: String): T } a

    class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a val mapper = IntMapper() hoge(mapper) ❌
  62. interface Mapper<out T> { a fun map(s: String): T }

    a class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a val mapper = IntMapper() hoge(mapper) ❌
  63. interface Mapper<out T> { a fun map(s: String): T }

    a class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a val mapper = IntMapper() hoge(mapper) ❌
  64. interface Mapper<out T> { a fun map(s: String): T }

    a class IntMapper : Mapper<Int> { a override fun map(s: String): Int = s.toInt() } a fun hoge(mapper: Mapper<Number>) { a mapper.map("10") } a val mapper = IntMapper() hoge(mapper)
  65. ListͱMutableList public interface List<out E> : Collection<E> public interface MutableList<E>

    : List<E>, … • List͸outम০ࢠ͕෇͍͍ͯΔͷͰɺڞม • MutableList͸Կ΋෇͍͍ͯͳ͍ͷͰɺෆม
  66. val strs: List<String> = listOf("a", “b") val anys: List<Any> =

    strs val a: Any = anys[0] val a2: Any? = anys2.getOrNull(1)
  67. val strs: List<String> = listOf("a", “b") val anys: List<Any> =

    strs val a: Any = anys[0] val a2: Any? = anys2.getOrNull(1)
  68. PECS • Producer Extends Consumer Super • Producer͸readͷੑ࣭Λ࣋ͭ • Consumer͸writeͷੑ࣭Λ࣋ͭ

    • List͸Producerͷੑ࣭ͷΈΛ࣋ͭͷͰɺExtends = out ڞมʹ ग़དྷΔ • MutableList͸ProducerͱConsumerͷੑ࣭Λ࣋ͭͷͰɺෆม
  69. 2ͭҎ্ͷ্քΛ࣋ͭܕม਺ • 1ͭͷ্քʢupper boundʣΛ࣋ͭͱ͖͸ɺׅހ಺ʹॻ͚͹ྑ ͍ • fun <T : CharSequence>

    hoge(t: T) {…} • 2ͭҎ্ͷ্քΛ࣋ͭ৔߹͸Ͳ͏͢Ε͹Α͍͔ʁ • ྫ͑͹ɺActivity͔ͭOnClickListenerΛ࣋ͭܕΛड͚ೖΕΔܕ ม਺Λఆ͍ٛͨ͠
  70. class OnClickActivity() : Activity(), OnClickListener fun setClick(activity: OnClickActivity) { a

    } a val activity = OnClickActivity() setClick(activity) class OnClickActivity2() : Activity(), OnClickListener
  71. class OnClickActivity() : Activity(), OnClickListener fun setClick(activity: OnClickActivity) { a

    } a val activity = OnClickActivity() setClick(activity) class OnClickActivity2() : Activity(), OnClickListener val activity2 = OnClickActivity2() setClick(activity2)
  72. class OnClickActivity() : Activity(), OnClickListener fun setClick(activity: OnClickActivity) { a

    } a val activity = OnClickActivity() setClick(activity) class OnClickActivity2() : Activity(), OnClickListener val activity2 = OnClickActivity2() setClick(activity2) ❌
  73. fun <T> setClick(activity: T) where T : Activity, T :

    OnClickListener { a } a val activity = OnClickActivity() setClick(activity)
  74. fun <T> setClick(activity: T) where T : Activity, T :

    OnClickListener { } val activity = OnClickActivity() setClick(activity) val activity2 = OnClickActivity2() setClick(activity2)
  75. internal abstract class NIOSocketImpl<out S>( override val channel: S, val

    selector: SelectorManager, val pool: ObjectPool<ByteBuffer>? ) : ReadWriteSocket, SelectableBase(channel), CoroutineScope where S : java.nio.channels.ByteChannel, S : java.nio.channels.SelectableChannel Ktor
  76. internal abstract class NIOSocketImpl<out S>( override val channel: S, val

    selector: SelectorManager, val pool: ObjectPool<ByteBuffer>? ) : ReadWriteSocket, SelectableBase(channel), CoroutineScope where S : java.nio.channels.ByteChannel, S : java.nio.channels.SelectableChannel Ktor
  77. internal abstract class NIOSocketImpl<out S>( override val channel: S, val

    selector: SelectorManager, val pool: ObjectPool<ByteBuffer>? ) : ReadWriteSocket, SelectableBase(channel), CoroutineScope where S : java.nio.channels.ByteChannel, S : java.nio.channels.SelectableChannel internal class DatagramSocketImpl(override val channel: DatagramChannel, selector: SelectorManager) : BoundDatagramSocket, ConnectedDatagramSocket, NIOSocketImpl<DatagramChannel>(channel, selector, DefaultDatagramByteBufferPool) Ktor
  78. internal abstract class NIOSocketImpl<out S>( override val channel: S, val

    selector: SelectorManager, val pool: ObjectPool<ByteBuffer>? ) : ReadWriteSocket, SelectableBase(channel), CoroutineScope where S : java.nio.channels.ByteChannel, S : java.nio.channels.SelectableChannel internal class DatagramSocketImpl(override val channel: DatagramChannel, selector: SelectorManager) : BoundDatagramSocket, ConnectedDatagramSocket, NIOSocketImpl<DatagramChannel>(channel, selector, DefaultDatagramByteBufferPool) internal class SocketImpl<out S : SocketChannel>( override val channel: S, private val socket: java.net.Socket, selector: SelectorManager ) : NIOSocketImpl<S>(channel, selector, pool = null), Socket Ktor
  79. inline fun <reified T> hoge(obj: Any) { a println(T::class.java) a

    if (obj is T) { a println("obj is T") a } a } a
  80. inline fun <reified T> hoge(obj: Any) { a println(T::class.java) a

    if (obj is T) { a println("obj is T") a } a } a
  81. inline fun <reified T> hoge(obj: Any) { a println(T::class.java) a

    if (obj is T) { a println("obj is T") a } a } a
  82. class A<T>(val value: T) { a fun isNull(): Boolean {

    a return value != null } a } a val a1: A<Int?> = A(null) a a1.isNull() a
  83. class A<T>(val value: T) { a fun isNull(): Boolean {

    a return value != null } a } a val a1: A<Int?> = A(null) a a1.isNull() a val a2: A<Int> = A(10) a a2.isNull() a
  84. class A<T>(val value: T) a fun <T : Any> A<T?>.isNull():

    Boolean { a return value != null a } a val a1: A<Int?> = A(null) a a1.isNull() a val a2: A<Int> = A(10) a a2.isNull() a
  85. class A<T>(val value: T) a fun <T : Any> A<T?>.isNull():

    Boolean { a return value != null a } a val a1: A<Int?> = A(null) a a1.isNull() a val a2: A<Int> = A(10) a a2.isNull() a
  86. class A<T>(val value: T) a fun <T : Any> A<T?>.isNull():

    Boolean { a return value != null a } a val a1: A<Int?> = A(null) a a1.isNull() a val a2: A<Int> = A(10) a a2.isNull() a
  87. class A<T>(val value: T) a fun <T : Any> A<T?>.isNull():

    Boolean { a return value != null a } a val a1: A<Int?> = A(null) a a1.isNull() a val a2: A<Int> = A(10) a a2.isNull() a ❌
  88. abstract class Either object Left : Either() object Right :

    Either() when (obj) { a Left -> println("is Left") Right -> println("is Right") else -> println("else") } a
  89. sealed class Either object Left : Either() object Right :

    Either() when (obj) { a Left -> println("is Left") Right -> println("is Right") else -> println("else") } a
  90. sealed class Either object Left : Either() object Right :

    Either() when (obj) { a Left -> println("is Left") Right -> println("is Right") } a
  91. public abstract class Either { private Either() { } //

    $FF: synthetic method public Either(DefaultConstructorMarker $constructor_marker) { this(); } }
  92. public abstract class Either { private Either() { } //

    $FF: synthetic method public Either(DefaultConstructorMarker $constructor_marker) { this(); } }
  93. fun add(a1: Int, a2: Int): Int { a return a1

    + a2 } a add add(10, 20) val a: (Int, Int) -> Int = ::add
  94. fun add(a1: Int, a2: Int): Int { a return a1

    + a2 } a add add(10, 20) val a: (Int, Int) -> Int = ::add a(10, 20)
  95. } a add add(10, 20) val a: (Int, Int) ->

    Int = ::add a(10, 20) fun <P1, P2, R> ((P1, P2) -> R).curried(): (P1) -> (P2) -> R = { p1: P1 -> { p2: P2 -> this(p1, p2) } } a
  96. } a add add(10, 20) val a: (Int, Int) ->

    Int = ::add a(10, 20) fun <P1, P2, R> ((P1, P2) -> R).curried(): (P1) -> (P2) -> R = { p1: P1 -> { p2: P2 -> this(p1, p2) } } a
  97. } a add add(10, 20) val a: (Int, Int) ->

    Int = ::add a(10, 20) fun <P1, P2, R> ((P1, P2) -> R).curried(): (P1) -> (P2) -> R = { p1: P1 -> { p2: P2 -> this(p1, p2) } } a
  98. } a add add(10, 20) val a: (Int, Int) ->

    Int = ::add a(10, 20) fun <P1, P2, R> ((P1, P2) -> R).curried(): (P1) -> (P2) -> R = { p1: P1 -> { p2: P2 -> this(p1, p2) } } a val curried = a.curried()
  99. } a add add(10, 20) val a: (Int, Int) ->

    Int = ::add a(10, 20) fun <P1, P2, R> ((P1, P2) -> R).curried(): (P1) -> (P2) -> R = { p1: P1 -> { p2: P2 -> this(p1, p2) } } a val curried = a.curried() curried(10)(20)
  100. class A : (Int) -> Unit { a override fun

    invoke(p1: Int) { a println("call $p1") } a } a val a = A() a.invoke(10)
  101. class A : (Int) -> Unit { a override fun

    invoke(p1: Int) { a println("call $p1") } a } a val a = A() a(10)
  102. public interface Function1<in P1, out R> : Function<R> { public

    operator fun invoke(p1: P1): R } a val a: (Number) -> Number = { it } a
  103. public interface Function1<in P1, out R> : Function<R> { public

    operator fun invoke(p1: P1): R } a val a: (Number) -> Number = { it } a val a1: (Int) -> Number = a
  104. public interface Function1<in P1, out R> : Function<R> { public

    operator fun invoke(p1: P1): R } a val a: (Number) -> Number = { it } a val a1: (Int) -> Number = a
  105. public interface Function1<in P1, out R> : Function<R> { public

    operator fun invoke(p1: P1): R } a val a: (Number) -> Number = { it } a val a1: (Int) -> Number = a val a2: (Number) -> Any = a
  106. public interface Function1<in P1, out R> : Function<R> { public

    operator fun invoke(p1: P1): R } a val a: (Number) -> Number = { it } as val a1: (Int) -> Number = a val a2: (Number) -> Any = a
  107. SAMม׵ • SAM? • Single Abstract Method • 1ͭͷந৅ϝιουΛ࣋ͭ •

    Kotlin͔ΒJavaఆٛͷSAMΛ࢖͏ͱ͖ʹɺϥϜμࣜͰ؆ܿʹ ॻ͘͜ͱ͕ग़དྷΔ
  108. public class SamTest { a public static void foo(Runnable a,

    Runnable b) { a } a } a fun test() { a SamTest.foo({}) { a } a } a
  109. public class SamTest { a public static void foo(Runnable a,

    Runnable b) { a } a } a fun test() { a SamTest.foo({}) { a } a } a public interface Runnable { public abstract void run(); }
  110. public class SamTest { a public static void foo(Runnable a,

    Runnable b) { a } a } a fun test(r: Runnable) { a SamTest.foo(r) { } } a
  111. public class SamTest { a public static void foo(Runnable a,

    Runnable b) { a } a } a fun test(r: Runnable) { a SamTest.foo(r) { } } a ❌
  112. // RxJava val o1 = Observable.just(1) val o2 = Observable.just(2)

    val combination = Observable .combineLatest(o1, o2, { n1, n2 -> n1 to n2 }) a
  113. // RxJava val o1 = Observable.just(1) val o2 = Observable.just(2)

    val combination = Observable .combineLatest(o1, o2, { n1, n2 -> n1 to n2 }) public static <T1, T2, R> Observable<R> combineLatest( ObservableSource<? extends T1> source1, ObservableSource<? extends T2> source2, BiFunction<? super T1, ? super T2, ? extends R> combiner ) a
  114. // RxJava val o1 = Observable.just(1) val o2 = Observable.just(2)

    val combination = Observable .combineLatest(o1, o2, { n1, n2 -> n1 to n2 }) public static <T1, T2, R> Observable<R> combineLatest( ObservableSource<? extends T1> source1, ObservableSource<? extends T2> source2, BiFunction<? super T1, ? super T2, ? extends R> combiner ) a public interface ObservableSource<T> { a void subscribe(@NonNull Observer<? super T> observer); } ˇ
  115. // RxJava val o1 = Observable.just(1) val o2 = Observable.just(2)

    val combination = Observable .combineLatest(o1, o2, { n1, n2 -> n1 to n2 })
  116. // RxJava val o1 = Observable.just(1) val o2 = Observable.just(2)

    val combination = Observable .combineLatest(o1, o2, { n1, n2 -> n1 to n2 }) ❌
  117. // RxJava val o1 = Observable.just(1) val o2 = Observable.just(2)

    val combination = Observable .combineLatest(o1, o2, BiFunction { n1, n2 -> n1 to n2 })
  118. public static <T1, T2, R> Observable<R> combineLatest( ObservableSource<? extends T1>

    source1, ObservableSource<? extends T2> source2, BiFunction<? super T1, ? super T2, ? extends R> combiner ) a
  119. public static <T1, T2, R> Observable<R> combineLatest( Observable<? extends T1>

    source1, Observable<? extends T2> source2, BiFunction<? super T1, ? super T2, ? extends R> combiner ) a
  120. public static <T1, T2, R> Observable<R> combineLatest( Observable<? extends T1>

    source1, Observable<? extends T2> source2, BiFunction<? super T1, ? super T2, ? extends R> combiner ) a val o1 = Observable.just(1) val o2 = Observable.just(2) val combination = Observable .combineLatest(o1, o2, BiFunction { n1, n2 -> n1 to n2 })
  121. public static <T1, T2, R> Observable<R> combineLatest( Observable<? extends T1>

    source1, Observable<? extends T2> source2, BiFunction<? super T1, ? super T2, ? extends R> combiner ) a val o1 = Observable.just(1) val o2 = Observable.just(2) val combination = Observable .combineLatest(o1, o2, { n1, n2 -> n1 to n2 })
  122. Kotlin Fest 2019 ࠤ౻ ൏ / Sato Shun Twitter: @stsn_jp

    GitHub: satoshun Kotlinܕ࣮ફೖ໳