TODO():Nothingなので、
- TODO()に続くコードは到達不能にできる。
fun shouldReturnAString():String{ TODO("まだ開発途中") println("TODOのした") //到達しない }
enum class Direction() { NORTH, EAST, SOUTH, WEST } fun main(){ println("Direction.NORTH = ${Direction.NORTH}") println("Direction.NORTH.name = ${Direction.NORTH.name}") println("Direction.NORTH.ordinal = ${Direction.NORTH.ordinal}") println("Direction.EAST = ${Direction.EAST}") println("Direction.EAST.name = ${Direction.EAST.name}") println("Direction.EAST.ordinal = ${Direction.EAST.ordinal}") } ↓ Direction.NORTH = NORTH Direction.NORTH.name = NORTH Direction.NORTH.ordinal = 0 Direction.EAST = EAST Direction.EAST.name = EAST Direction.EAST.ordinal = 1
enum class Direction(val x:Int,val y:Int) { NORTH(0,-1), EAST(1,0), SOUTH(0,1), WEST(-1,0) } fun main(){ println("Direction.NORTH.x = ${Direction.NORTH.x}") println("Direction.NORTH.y = ${Direction.NORTH.y}") println("Direction.NORTH = ${Direction.NORTH}") println("Direction.NORTH.name = ${Direction.NORTH.name}") println("Direction.NORTH.ordinal = ${Direction.NORTH.ordinal}") println("Direction.EAST.x = ${Direction.EAST.x}") println("Direction.EAST.y = ${Direction.EAST.y}") println("Direction.EAST = ${Direction.EAST}") println("Direction.EAST.name = ${Direction.EAST.name}") println("Direction.EAST.ordinal = ${Direction.EAST.ordinal}") } ↓ Direction.NORTH.x = 0 Direction.NORTH.y = -1 Direction.NORTH = NORTH Direction.NORTH.name = NORTH Direction.NORTH.ordinal = 0 Direction.EAST.x = 1 Direction.EAST.y = 0 Direction.EAST = EAST Direction.EAST.name = EAST Direction.EAST.ordinal = 1
ジェネリック型とはどんな型でも入力として受けとるコンストラクタを持つ型。
Class Class名<T>(xxxx:T)
class LootBox<T>(var item:T) class Fedora(val name:String,val value:Int) class Coin(val value:Int) fun main(){ // ジェネリックを使っているのでFedoraでもCoinでもいれることができる val lootBoxOne:LootBox<Fedora> = LootBox(Fedora("general-fedora",15)) val lootBoxTow:LootBox<Coin> = LootBox(Coin(15)) }
class LootBox<T>(var item:T){ fun fetch():T{ //関数でもジェネリックが使える return item } } class Fedora(val name:String,val value:Int) class Coin(val value:Int) fun main(){ // ジェネリックを使っているのでFedoraでもCoinでもいれることができる val lootBoxOne:LootBox<Fedora> = LootBox(Fedora("general-fedora",15)) val lootBoxTow:LootBox<Coin> = LootBox(Coin(15)) lootBoxOne.fetch().run { println("You Retrive $name") } } ↓ You Retrive general-fedora
fun <R> 関数名():R
class LootBox<T>(var item:T){ fun fetch():T{ return item } fun <R> fetch(lootFunction:(T)->R):R{ //戻り値に新しいジェネリックを追加 return lootFunction(item) } } class Fedora(val name:String,val value:Int) class Coin(val value:Int) fun main(){ // ジェネリックを使っているのでFedoraでもCoinでもいれることができる val lootBoxOne:LootBox<Fedora> = LootBox(Fedora("general-fedora",15)) val lootBoxTow:LootBox<Coin> = LootBox(Coin(15)) //val price = lootBoxOne.fetch<Int>({it.value*5}) //val price = lootBoxOne.fetch<Int>(){it.value*5} //ラムダの引数は外にだす val price = lootBoxOne.fetch(){it.value*5} //型の<Int>は省略できる println(price) }
class LootBox<T:Loot>(var item:T){ //<T>を<T:Loot>とすることでジェネリック型の制約ができる。 fun fetch():T{ return item } } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) //FedoraはLootのサブクラス class Coin(value:Int) // Coinはサブクラスではない fun main(){ val lootBoxOne:LootBox<Loot> = LootBox(Fedora("general-fedora",15)) //FedoraはサブクラスなのでLoot型の箱に入る。 //val fedora:Fedora = lootBoxOne.item // Error Required:Fedora Found:Loot // Loot型の箱に入れるとFedoraという情報は消える //val lootBoxTwo = LootBox(Coin(15))} // CoinはLootのサブクラスではないので箱にははいらなくなった。←ジェネリック型の制約
ジェネリック不変なので下記コードはエラーとなることが大前提!
val lootOnebox = LootBox(Fedora("cool-Fedora!",30)) val lootBox:LootBox<Loot> = lootOnebox //ジェネリックは不変
// このコードはエラー!! class LootBox<T>(val item:T){ // outが必要 } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) //Lootのサブクラス class Coin(value:Int):Loot(value) //Lootのサブクラス fun main() { val coinBox:LootBox<Coin> = LootBox(Coin(15)) val lootBox1:LootBox<Loot> = coinBox //ジェネリック型は不変なのでエラー!! LootBox<Loot> LootBox<Coin> val lootBox2:LootBox<Loot> = LootBox(Coin(15)) // これはインスタンスの代入ではないのでoutがなくても可能。 }
↓
class LootBox<out T>(val item:T){ //outをつけるとコンパイルが通る。outにするとvarにはできない。 } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) //Lootのサブクラス class Coin(value:Int):Loot(value) //Lootのサブクラス fun main() { val coinBox:LootBox<Coin> = LootBox(Coin(15)) val lootBox:LootBox<Loot> = coinBox // コンパイルできる!が、Coinの情報はなくなりLootになる。 }
// 不変によりLootBox<Fedora>型のインスタンスをLootBox<Loot>型に代入することはできない。 val lootOnebox = LootBox(Fedora("cool-Fedora!",30)) val lootBox:LootBox<Loot> = lootOnebox //←エラー。outを使う必要がある。 // しかしLootBox<Loot>型を使ってFedoraの初期値をもつLootBoxのインスタンスを成することはできる。 // 作成した段階で、Fedoraの情報は失われてLootBox<Loot>型のインスタンスとなる。 val lootBoxThird:LootBox<Loot> = LootBox(Fedora("cool-Fedora!",30)) // ←正常
↓スマートキャスト
class LootBox<out T>(val item:T){ //outをつける!! } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) //Lootのサブクラス class Coin(value:Int):Loot(value) //Lootのサブクラス fun main() { val fedorBox = LootBox(Fedora("cool-Fedora!",30)) var lootBox:LootBox<Loot> = LootBox(Coin(10)) val myLoot = lootBox.item // Coin型ではなくLoot型にスマートキャストされる lootBox=fedorBox // outがないとLootBxo<Loot>にLootBox<Fedora>は代入できない。 val myFedora = lootBox.item //LootBox<Loot>だが、Fedora型へスマートキャストできる! }
class LootBox<in T>(item:T){ //inをつけるとvalやvarはつけれれない。プロパティとなり値を返してしまう(生産者となる)から。 // private var loot = item // fun fetch():T{ //inがあるとこのような関数も作成できない // return loot // } } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) //Lootのサブクラス class Coin(value:Int):Loot(value) //Lootのサブクラス fun main() { var fedorBox = LootBox(Fedora("cool-Fedora!",30)) var lootBox:LootBox<Loot> = LootBox(Coin(10)) fedorBox = lootBox //in があるとLootBox<Fedora>型にLootBxo<Loot>が代入できる // val myFedora = fedorBox.item //エラー!inがあるので生産できない! }
そもそも通常のインスタンスの場合は、上位クラス = 下位クラス は可能。
ジェネリック型の場合は、同じレベルのクラス = 同じレベルのクラス が基本(=不変)。
class LootBox<T>(val item:T){ //inをつけるとvalやvarはつけれれない。プロパティとなり値を返してしまう(生産者)から。 } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) class Coin(value:Int):Loot(value) fun main() { // Loot型にcoin型をいれることはできる。 val coinItem:Coin = Coin(15) val LootItem:Loot = coinItem // ジェネリック型にcoin型をいれることはできない。不変! val coinBox = LootBox(Coin(20)) val lootBox:LootBox<Loot> = coinBox // type mismatchでエラー。LootBox<out T>にする必要がある。 ↓ // キャストすることも可能だが、UnChecked Castと警告がでる。 val lootBox:LootBox<Loot> = coinBox as LootBox<Loot> }
outはLootBox<Loot>型を指定して、LootBox<Coin>型のインスタンスがつくれないというはなしではない。
もしそうしても、LootBox<Loot>型のインスタンスが作成されるだけだ。
LootBox<Loot>型のインスタンスにLootBox<Coin>型のインスタンスを代入できない。
<Loot>型なのに中身が<Coin>型や<Fedora>型になってしまうため。
class LootBox<T>(val item:T){ } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) class Coin(value:Int):Loot(value) fun main() { // outがなくてもLootBox<Loot>型でLootBox<Coin>型を作ることはできる。 val lootBox1:LootBox<Loot> = LootBox(Coin(10)) val coin1:Coin = lootBox1.item // エラー。Coin型の情報はなくなり、Loot型になっている。 val coin2:Coin = lootBox1.item as Coin // キャストしてやれば取り出せる。 //LootBox<Coin>でインスタンスを作成したものをLootBox<Loot>型に変換できない。 val coinBox = LootBox(Coin(20)) val lootBox2:LootBox<Loot> = coinBox //エラー。 LootBox<out T>(val item:T)にする必要がある。 ↓ // outをつけると下記コードは通り、LootBox<Coin>型からLootBox<Loot>へ変換される。 val lootBox2:LootBox<Loot> = coinBox }
ジェネリック型は型消去されて実行時に型情報を利用できない。
class LootBox<T>(val item:T){ } open class Loot(val value:Int) class Fedora(val name:String,value:Int):Loot(value) //Lootのサブクラス class Coin(value:Int):Loot(value) //Lootのサブクラス inline fun <reified T> randomOrBackupLoot(backupLoot:()->T):T { //reifiedにはinlineが必要 val items = listOf(Coin(14), Fedora("good-fedora", 20)) val randomLoot: Loot = items.shuffled().first() return if (randomLoot is T){ //reifiedがないとTでエラー randomLoot }else{ backupLoot() } } fun main() { randomOrBackupLoot { Fedora("backup-fedora",99) }.run { println("$name") } }
fun <T : Any> generateSequence( seed: T?, nextFunction: (T) -> T? ): Sequence<T> ↓ generateSequence([初期値],[ラムダ]) ↓ generateSequence([初期値]){[ラムダ]}
fun Int.isEven():Boolean{ return this%2==0 } val seq = generateSequence(1) { it+1 }.take(10).filter { it.isEven() }.toList() println(seq) [2, 4, 6, 8, 10]
// seedはまずプリントされてから増加する generateSequence(1){it+1}.take(10).forEach { println(it) } 1 2 3
val gradesByStudent = mapOf("Josh" to 4.0,"Alex" to 2.0,"Jane" to 3.0) println(gradesByStudent) val reverseGradesByStudent= gradesByStudent.map { Pair(it.value,it.key) }.toMap() print(reverseGradesByStudent) {Josh=4.0, Alex=2.0, Jane=3.0} {4.0=Josh, 2.0=Alex, 3.0=Jane}
build.gradle(Module.app)
dependencies { ・・・ //implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5' // 古い implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2" // android (async, await) implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2' // launch Deferred ・・・ }
CharacterGenerator.kt
//import kotlinx.coroutines.experimental.Deferred //import kotlinx.coroutines.experimental.async // ↓ import kotlinx.coroutines.Deferred import kotlinx.coroutines.async import kotlinx.coroutines.GlobalScope // return async ⇒ GlobalScope.async fun fetchCharacterData(): Deferred<CharacterData> { return GlobalScope.async { val apiData=URL(CHARACTER_DATA_API).readText() CharacterGenerator.fromApiData(apiData) } } fun fromApiData(apiData:String):CharacterData{ val (race,name,dex,wis,str)= apiData.split(",") return CharacterData(name,race,dex,wis,str) }
NewCharacterActivity.kt
//import kotlinx.coroutines.experimental.android.UI //import kotlinx.coroutines.experimental.launch // ↓ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch // launch(UI) { ⇒ GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) { characterData = CharacterGenerator.fetchCharacterData().await() displayCharacterDate() }