この文書の現在のバージョンと選択したバージョンの差分を表示します。
| 両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
|
kotlin:kotlinプログラミング [2019/12/01 09:49] ips [17.6 in と out] |
kotlin:kotlinプログラミング [2019/12/10 08:10] (現在) ips |
||
|---|---|---|---|
| ライン 19: | ライン 19: | ||
| ===== 15.4 列挙クラス ===== | ===== 15.4 列挙クラス ===== | ||
| + | |||
| + | |||
| + | [[kotlin:enumとsealed|]] | ||
| <code kotlin> | <code kotlin> | ||
| ライン 83: | ライン 86: | ||
| Class Class名<T>(xxxx:T) | Class Class名<T>(xxxx:T) | ||
| - | <code> | + | <code kotlin> |
| class LootBox<T>(var item:T) | class LootBox<T>(var item:T) | ||
| ライン 98: | ライン 101: | ||
| ===== 17.2 ジェネリック関数 ===== | ===== 17.2 ジェネリック関数 ===== | ||
| - | <code> | + | <code kotlin> |
| class LootBox<T>(var item:T){ | class LootBox<T>(var item:T){ | ||
| fun fetch():T{ //関数でもジェネリックが使える | fun fetch():T{ //関数でもジェネリックが使える | ||
| ライン 123: | ライン 126: | ||
| ===== 17.3 複数のジェネリック型パラメータ ===== | ===== 17.3 複数のジェネリック型パラメータ ===== | ||
| - | <code> | + | fun <R> 関数名():R |
| + | |||
| + | <code kotlin> | ||
| class LootBox<T>(var item:T){ | class LootBox<T>(var item:T){ | ||
| fun fetch():T{ | fun fetch():T{ | ||
| ライン 150: | ライン 155: | ||
| ===== 17.4 ジェネリック型の制約 ===== | ===== 17.4 ジェネリック型の制約 ===== | ||
| - | <code> | + | <code kotlin> |
| class LootBox<T:Loot>(var item:T){ //<T>を<T:Loot>とすることでジェネリック型の制約ができる。 | class LootBox<T:Loot>(var item:T){ //<T>を<T:Loot>とすることでジェネリック型の制約ができる。 | ||
| fun fetch():T{ | fun fetch():T{ | ||
| ライン 177: | ライン 182: | ||
| - | <code> | + | <code kotlin> |
| // このコードはエラー!! | // このコードはエラー!! | ||
| - | class LootBox<T>(val item:T){ | + | class LootBox<T>(val item:T){ // outが必要 |
| } | } | ||
| ライン 188: | ライン 193: | ||
| fun main() { | fun main() { | ||
| val coinBox:LootBox<Coin> = LootBox(Coin(15)) | val coinBox:LootBox<Coin> = LootBox(Coin(15)) | ||
| - | // val lootBox:LootBox<Loot> = coinBox //ジェネリック型は不変なのでエラーLootBox<Loot> LootBox<Coin> | + | val lootBox1:LootBox<Loot> = coinBox //ジェネリック型は不変なのでエラー!! LootBox<Loot> LootBox<Coin> |
| + | val lootBox2:LootBox<Loot> = LootBox(Coin(15)) // これはインスタンスの代入ではないのでoutがなくても可能。 | ||
| } | } | ||
| </code> | </code> | ||
| ↓ | ↓ | ||
| - | <code> | + | <code kotlin> |
| class LootBox<out T>(val item:T){ //outをつけるとコンパイルが通る。outにするとvarにはできない。 | class LootBox<out T>(val item:T){ //outをつけるとコンパイルが通る。outにするとvarにはできない。 | ||
| } | } | ||
| ライン 220: | ライン 226: | ||
| ↓スマートキャスト | ↓スマートキャスト | ||
| - | <code> | + | <code kotlin> |
| class LootBox<out T>(val item:T){ //outをつける!! | class LootBox<out T>(val item:T){ //outをつける!! | ||
| } | } | ||
| ライン 237: | ライン 243: | ||
| lootBox=fedorBox // outがないとLootBxo<Loot>にLootBox<Fedora>は代入できない。 | lootBox=fedorBox // outがないとLootBxo<Loot>にLootBox<Fedora>は代入できない。 | ||
| val myFedora = lootBox.item //LootBox<Loot>だが、Fedora型へスマートキャストできる! | val myFedora = lootBox.item //LootBox<Loot>だが、Fedora型へスマートキャストできる! | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | <code kotlin> | ||
| + | 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があるので生産できない! | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | ===== 17.6.補足 in と out ===== | ||
| + | |||
| + | そもそも通常のインスタンスの場合は、上位クラス = 下位クラス は可能。 | ||
| + | ジェネリック型の場合は、同じレベルのクラス = 同じレベルのクラス が基本(=不変)。 | ||
| + | <code kotlin> | ||
| + | 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> | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | outはLootBox<Loot>型を指定して、LootBox<Coin>型のインスタンスがつくれないというはなしではない。 | ||
| + | もしそうしても、LootBox<Loot>型のインスタンスが作成されるだけだ。 | ||
| + | |||
| + | LootBox<Loot>型のインスタンスにLootBox<Coin>型のインスタンスを代入できない。 | ||
| + | <Loot>型なのに中身が<Coin>型や<Fedora>型になってしまうため。 | ||
| + | |||
| + | <code kotlin> | ||
| + | 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 | ||
| + | } | ||
| + | </code> | ||
| + | ===== 17.7 もっと知りたい? reifiedキーワード ===== | ||
| + | |||
| + | ジェネリック型は型消去されて実行時に型情報を利用できない。 | ||
| + | |||
| + | <code kotlin> | ||
| + | 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") } | ||
| } | } | ||
| </code> | </code> | ||