Edited at

【Kotlin】複数の値を返したい!

関数から複数の値を返したいこと、ありますよね!?


2つの値を1つにまとめる(Pair

2つの値を1つにまとめたいときは Pair クラスを使いましょう。

fun getNameAndVersion(): Pair<String, Double> {

return Pair("Kotlin", 1.3)
}

fun main() {
val nameAndVersion = getNameAndVersion()
val name = nameAndVersion.first // -> "Kotlin"
val version = nameAndVersion.second // -> 1.3
}

1つ目の値は first プロパティで、2つ目の値は second プロパティで、それぞれ取り出せます。


Pair インスタンスを簡単に作る(to

to 関数を使うと簡単に Pair インスタンスを作れます。

fun getNameAndVersion(): Pair<String, Double> {

return "Kotlin" to 1.3
}

2項演算子のように2つの値の間に置けます。(中置記法(infix notation) というやつです。)


返り値を2つの値として受け取る(分解宣言)

2つの値を Pair オブジェクトとしてではなく2つの値として受け取ることもできます。(分解宣言(Destructuring Declarations) と言います。1

fun main() {

val (name, version) = getNameAndVersion()
}


3つの値を返す(Triple

3つの値をまとめたいときは Triple クラスを使いましょう。

val triple = Triple("Kotlin", 1.3, 2018)

to 関数のようなものはなさそうです。

値はプロパティ firstsecondthird で取り出せます。

val name = triple.first // -> "Kotlin"

val version = triple.second // -> 1.3
val release = triple.third // -> 2018

分解宣言も使えます。

val (name, version, release) = triple


4つ以上の値を返す(data class

4つ以上の値をまとめるクラスは標準ライブラリーには用意されていないようです。2

自作する必要がありますが、data class を使えば簡単です。

data class Lang(

val name: String,
val version: Double,
val release: Int,
val isGood: Boolean
)

val kotlin = Lang("Kotlin", 1.3, 2018, true)

分解宣言も使えます。

val (name, version, release, isGood) = kotlin


おまけ:分解宣言についてもう少し


ラムダ式の引数にも使える

ラムダ式の引数部分でも分解宣言を使えます。

listOf(

0 to 'A',
1 to 'B',
2 to 'C'
).forEach { (number, alphabet) ->
println("$number: $alphabet")
}


分解宣言の入れ子はできない

分解宣言を入れ子にすることはできないようです。

val numbers = (1 to 1L) to (1.0 to 1.0F)

val ((i, l), (d, f)) = numbers // コンパイルエラー!


自作クラスでも使えるようにできる

PairTripledata class で分解宣言を使えるとお伝えしましたが、これらのクラスが特別扱いされているわけではありません。

自作のクラスでも使えるようにすることができます。

class Lang(

val name: String,
val version: Double,
val release: Int,
val isGood: Boolean
) {
operator fun component1() = name
operator fun component2() = version
operator fun component3() = release
operator fun component4() = isGood
}

fun main() {
val kotlin = Lang("Kotlin", 1.3, 2018, true)
val (name, version, release, isGood) = kotlin
}

前出の Lang クラスを data class ではない普通のクラスにしました。

代わりに componentNN は 1 始まりの整数)という operator 関数を追加しています。

これで data class のときと同様に分解宣言が使えます。

このように分解宣言の N 番目の引数(?)にしたい値を componentN という名前の operator 関数で返すようにすれば、自作のクラスでも分解宣言を使えるようになります。

data class ではこの componentN を自動的に実装してくれます。

そして PairTriple は実は data class です。(それぞれのリンク先をご確認ください。)

そういうわけで PairTripledata class では分解宣言を使えるのです。





  1. JavaScript では同様の機能が分割代入(Destructuring assignment)と呼ばれています。 



  2. 以前はあったとか…