1. 引数の型を List とした場合の型判定
fun doSomething(arg: List<Any>): List<Int> =
when(arg) {
is List<Int> -> ...
is List<String> -> ...
else -> ...
}
これだと、3-4行目のis
によるキャストで Cannot check for instance of erased type
というエラーを生じた。
List<Any>
型は 、
"List型であることはわかるけど、中身の型の情報は持っていない"
つまり中身の型は消されている型(erased type
)となるので、引数arg
の型をこのように判定することはできない。
一方で、次のような型判定は可能である。
fun doSomething(arg: List<Any>): List<Int> =
when(arg[0]) {
is Int -> ...
is String -> ...
else -> ...
}
arg
の"要素"はAny
型なので、これらはis
を用いて判定することができる。
2. アスタリスク(*)とAnyの違い
fun doSomething(arg: List<*>): List<Int> =
when(arg[0]) {
is Int -> ...
is String -> ...
else -> ...
}
Any
が「なんでも受け入れる型」を意味するのに対し、*
は「型はわからないけど、今は重要じゃないから伏せ字にしておく」くらいの感覚。
したがって、List<Any>
と List<*>
では、それぞれ次のような挙動になる。
val foo = listOf("bar") //fooの型はList<String>となる。
foo is List<Any> //fooはList<Any>型ではないのでfalse
foo is List<*> //fooは「何かしらのList」型なのでtrue
3. ラムダ式の戻り値 (あるいはブロックとreturn
について)
map
,filter
,reduce
,fold
のようなfunctional loopを使うと、綺麗にコードがかける場合が多い。
kotlinでは、これらのfunctional loopは、引数としてラムダ式をとる。
例として、次のような配列を考える。
val sampleList = listOf(1,2,3,4,5)
これらの配列の各要素を2倍にしたいとき、オブジェクト指向言語ではmap
関数を使う。
kotlinでは、Iterable
インターフェース1が実装されていればmap
関数を呼び出すことができる。
目的のラムダ式は次のように書ける。
{ x:Int -> x * 2}
kotlinのマップ関数は、引数にラムダ式を取り、ラムダ式の引数に各要素を代入するので、次のように書けば良い。
val result = sampleList.map {x:Int -> x * 2}
// result == [2,4,6,8,10]
この時return
を書くとmap
を抜けてしまう。
sampleList.map {x:Int -> return x * 2}
// 戻り値は4だが、mapよりも上のレベルで return されてしまった。
ラムダ式の->
後にはブロック{...}
として渡すこともできるが、ブロックの値そのものが返る。
val result = sampleList.map {x:Int -> {
x * 2
}}
// => result == [
// Function0<java.lang.Integer>,
// Function0<java.lang.Integer>,
// Function0<java.lang.Integer>,
// Function0<java.lang.Integer>,
// Function0<java.lang.Integer>
// ]
ブロックを渡した際には、ブロック内でreturn
するとエラーとなる。
sampleList.map {x:Int -> {
return x * 2
}} // エラー => " 'return' is not allowed here "
ラムダ式では、最後の評価値が返される。
val result = sampleList.map {x:Int ->
x * 2
x * 3
} // result == [3,6,9,12,15]
val result = sampleList.map {x:Int -> {
x * 2
var a = x + 1
}}
// => result == [
// kotlin.Unit,
// kotlin.Unit,
// kotlin.Unit,
// kotlin.Unit,
// kotlin.Unit
// ]
// あくまで「代入した」という処理の結果が返る。
追加でわかったことがあればアップデートします。
-
List
やArray
など、順番に取り出せるもの ↩