Skip to content

Instantly share code, notes, and snippets.

@SatoTakeshiX SatoTakeshiX/Main.kt
Last active Jan 9, 2018

Embed
What would you like to do?
Kotlinスタートブック11章 ジェネリクス
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> //THogeのサブタイプでなければいけない
//複数の上限境界を設定
interface Piyo: Hoge, Fuga
class Baz<T> where T : Hoge, T: Fuga //THogeFugaのサブタイプでなければいけない
/*
* 変位指定
* 一般的な意味
* 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
@SatoTakeshiX

This comment has been minimized.

Copy link
Owner Author

commented Jan 8, 2018

ライセンスはMITにします。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.