Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

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. 以前はあったとか… 

sdkei
Kotlin かわいい。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away