Last active
January 9, 2018 00:50
-
-
Save SatoTakeshiX/a12d93bf103532a873e85fd4d0aed0ff to your computer and use it in GitHub Desktop.
Kotlinスタートブック11章 ジェネリクス
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fun main(args: Array<String>){ | |
// いろんな型を扱う方法->Any型で扱ってみる。値を操作するときはキャストする | |
var intContainer = ContainerAny(123) | |
var i: Int = intContainer.value as Int //valueをasでダウンキャストしてIntとして扱う | |
println(i) //->123と表示 | |
var strContainer = ContainerAny("Hello") | |
var s = strContainer.value as String //valueをasでダウンキャストしてStringとして扱う | |
println(s) //-> Helloが表示 | |
/** | |
* ダウンキャストは危険な操作。 | |
* 失敗することもある | |
*/ | |
//値123をIntではなくStringでキャストをするとClassCastExceptionをスローする。 | |
//Container(123).value as String | |
//ジェネリクスを使う | |
var intContainerGeneric: ContainerGeneric<Int> = ContainerGeneric<Int>(123) | |
val ig: Int = intContainerGeneric.value | |
println(ig * 2) | |
var strContainerGeneric: ContainerGeneric<String> = ContainerGeneric<String>("Hello") | |
val sg: String = strContainerGeneric.value | |
println(sg.toUpperCase()) | |
//ジェネリクスを関数で扱う | |
val containerFromFun: ContainerGeneric<Int> = box(5) | |
//ジェネリクス関数の実行例 | |
println(containerFromFun.string) | |
/** | |
* p161 | |
* ジェネリック制約 | |
*/ | |
Foo<Hoge>() //OK->Foo<T>のTはなんでもいい | |
Foo<Fuga>() //OK->Foo<T>のTはなんでもいい | |
Bar<Hoge>() //OK->Bar<T: Hoge>のHogeのサブタイプ | |
//Bar<Fuga>() //NG->Bar<T: Hoge>なのでFugaはHogeでなければいけない | |
//複数の上限境界を設定 | |
Baz<Piyo>() | |
//変位指定 | |
invariantSample() | |
contravariantSample() | |
declarationSiteVarianceSample() | |
starProjectionSample() | |
//具象型 | |
println("String".instanceOf<String>())//->true | |
println((0.5).instanceOf<Int>())//->false | |
println(setOf("4").instanceOf<Set<Char>>())//true | |
} | |
//Anyを使っていろんな型に対応する | |
//valueはAnyになる | |
class ContainerAny(var value: Any) | |
// ジェネリクスを使っていろんな型に対応する | |
class ContainerGeneric<T>(var value: T) | |
// ジェネリクス関数 | |
fun <T> box(value: T): ContainerGeneric<T> = | |
ContainerGeneric(value) | |
val <T> T.string: String | |
get() = toString() | |
/* | |
p161 | |
* ジェネリック制約 | |
*/ | |
interface Hoge | |
interface Fuga | |
class Foo<T> //Tの制約なし | |
class Bar<T : Hoge> //TはHogeのサブタイプでなければいけない | |
//複数の上限境界を設定 | |
interface Piyo: Hoge, Fuga | |
class Baz<T> where T : Hoge, T: Fuga //TはHogeとFugaのサブタイプでなければいけない | |
/* | |
* 変位指定 | |
* 一般的な意味 | |
* https://ja.wikipedia.org/wiki/%E5%85%B1%E5%A4%89%E6%80%A7%E3%81%A8%E5%8F%8D%E5%A4%89%E6%80%A7_(%E8%A8%88%E7%AE%97%E6%A9%9F%E7%A7%91%E5%AD%A6) | |
* | |
* 型を狭いものから広いものの順に順序づけたとき、それらの間に互換性あること | |
* 共変 (covariant): 広い型(例:double)から狭い型(例:float)へ変換すること。 | |
* 反変 (contravariant) : 狭い型(例:float)から広い型(例:double)へ変換すること。 | |
* 不変 (invariant): 型を変換できないこと。 | |
* 双変 (bivariant): 広い型にも狭い型にも変換できること。 | |
* | |
* | |
// p165 変位指定まとめ | |
* 不変 | |
* invariant | |
* 修飾子なし | |
* AがBのサブタイプのとき | |
* ->X<A>とX<B>の間にサブタイプの関係がなりたたない | |
* 入出力が操作可能(ゲッターセッターできる) //??同じ型同士ならゲッターセッター出来るということ?? | |
*/ | |
/* | |
* 共変 | |
* covariant | |
* 修飾子:out | |
* AがBのサブタイプのとき | |
* ->X<A>はX<B>のサブタイプとなる | |
* 出力操作が可能(ゲッターできる) | |
* | |
*/ | |
/* | |
* 反変 | |
* contravariant | |
* 修飾子:in | |
* AがBのサブタイプのとき | |
* -> X<A>はX<B>のスーパータイプとなる | |
* 入力操作が可能(セッターできる) | |
* | |
*/ | |
//不変:invariant | |
fun invariantSample():Unit { | |
println("invariantSample") | |
//不変 | |
val a: ContainerGeneric<String> = ContainerGeneric("Hello") | |
//CharSequenceはStringのスーパータイプだけどKotlinはデフォルトでinvariant(不変)なので代入ができない | |
//val b: ContainerGeneric<CharSequence> = a // Type Mismatch | |
//不変だと余り訳にたたないコード | |
fun show(container: ContainerGeneric<Any>) { | |
println(container.toString()) | |
println(container.hashCode()) | |
println(container.value) | |
} | |
show(container = ContainerGeneric("invariantShow")) | |
} | |
/* | |
p163 | |
型投影(Type projection) | |
ジェネリックで指定した型をどのように変更するのかを指定する方法 | |
*/ | |
/* | |
共変(covariant)させる。 | |
広い型(スーパータイプ)から狭い方(サブタイプ)に変更する | |
*/ | |
fun covariantSample():Unit { | |
//共変として操作するにはout 修飾子をつける | |
fun show(containe: ContainerGeneric<out Any>) { | |
println(containe.toString()) | |
println(containe.hashCode()) | |
println(containe.value) | |
} | |
val a : ContainerGeneric<String> = ContainerGeneric("Hello") | |
val b: ContainerGeneric<out Any> = a //OK | |
//out修飾子で共変指定にしたので、値を他の型で書き換えすることはできなくなった | |
//Any型なのでなんでも代入できるはずなのに! | |
//b.value = 123 //Setter for value is removed by type projection. | |
//佐藤疑問。Stringのスーパータイプなら良い? | |
var c: ContainerGeneric<out CharSequence> = a | |
// c.value = "s" //やっぱりだめ | |
} | |
/** | |
* p164 | |
* 反変。サブタイプからスーパータイプに変換する | |
*/ | |
fun contravariantSample(): Unit { | |
//Containerクラスにオブジェクトをコピーするメソッドを定義する | |
class ContainerGeneric2<T>(var value: T) { | |
fun copyTo(to : ContainerGeneric2<in T>) {//in修飾子を使った反変指定する | |
to.value = value | |
} | |
} | |
val a: ContainerGeneric2<Int> = ContainerGeneric2(15) | |
val b: ContainerGeneric2<Number> = ContainerGeneric2(0) | |
a.copyTo(b) | |
println(b.value) | |
} | |
/** | |
* p165宣言場所変位指定 | |
* クラスを定義するところで変位を指定する。 | |
* プロパティアクセスするのにクラス内のメソッド引数にいちいち変位指定(inとかoutとか)をする必要がなくなる | |
*/ | |
fun declarationSiteVarianceSample():Unit { | |
//Tに対して共変なContainerを作る | |
//??outをなくしてもvalなので同じ結果になる? | |
class ContainerImmutable<out T>(val value:T) | |
fun show(container: ContainerImmutable<Any>) { | |
println(container.toString()) | |
println(container.hashCode()) | |
println(container.value) | |
} | |
show(ContainerImmutable(12)) | |
} | |
/* | |
p167 | |
スター投影 | |
in Nothingやout Any?のシンタックスシュガー | |
特定の型パラメーターを指定しないときに使う | |
Nothingはあらゆる型のサブタイプ。インスタンスは持たない。 | |
in Nothing -> Nothing型をin(セット)可能 -> Nothing型インスタンスは存在しない -> セット不可能 | |
スター投影->対象の型パラメーターに対応するオブジェクトの変更ができなくなり、取得時(ゲッター)には型Any?になる | |
*/ | |
fun starProjectionSample(){ | |
val a: ContainerGeneric<*> = ContainerGeneric<Int>(5) | |
val b: ContainerGeneric<*> = ContainerGeneric<String>("ABC") | |
} | |
/* | |
p168 | |
具象型 | |
型引数はランタイムで保持しない。 | |
*/ | |
fun reifiedSample(){ | |
//次の関数instanceOfは失敗する. | |
//fun <T>Any.instanceOf(): Boolean = this is T | |
} | |
//インライン関数にし、reified修飾子をつけると具象型にすることが出来る。 | |
inline fun<reified T>Any.instanceOf(): Boolean = this is T | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ライセンスはMITにします。