ユーザ用ツール

サイト用ツール


kotlin:kotlinプログラミング

差分

この文書の現在のバージョンと選択したバージョンの差分を表示します。

この比較画面にリンクする

両方とも前のリビジョン 前のリビジョン
次のリビジョン
前のリビジョン
kotlin:kotlinプログラミング [2019/12/01 09:46]
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にはできない。
 } }
ライン 219: ライン 225:
 </​WRAP>​ </​WRAP>​
  
-<​code>​+↓スマートキャスト 
 +<​code ​kotlin>
 class LootBox<​out T>(val item:​T){ ​ //​outをつける!! class LootBox<​out T>(val item:​T){ ​ //​outをつける!!
 } }
ライン 228: ライン 235:
  
 fun main() { fun main() {
-    // 不変によりLootBox<​Fedora>​型のインスタンスをLootBox<​Loot>​型に代入することはできない。+
     val fedorBox = LootBox(Fedora("​cool-Fedora!",​30))     val fedorBox = LootBox(Fedora("​cool-Fedora!",​30))
-    var lootBox:​LootBox<​Loot>​ = LootBox(Coin(10)) ​//​ジェネリックは不変!!LootBox<​out T>​にするとコンパイルできる!+    var lootBox:​LootBox<​Loot>​ = LootBox(Coin(10))
  
-    val myLoot = lootBox.item // Coin型ではなくLoot型にスマートキャスト+    val myLoot = lootBox.item // Coin型ではなくLoot型にスマートキャストされる
     ​     ​
     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>​
kotlin/kotlinプログラミング.1575161190.txt.gz · 最終更新: 2019/12/01 09:46 by ips