LoginSignup
4
1

More than 5 years have passed since last update.

Destructuring Declarations in Kotlin(社内勉強会用)

Last updated at Posted at 2018-11-21
1 / 18

Kotlin の Destructuring が微妙だという話をします


Destructuring Declarations in Kotlin

公式リファレンス https://kotlinlang.org/docs/reference/multi-declarations.html より

Sometimes it is convenient to destructure an object into a number of variables, for example:

val (name, age) = person

※ Syntax Highlight が変...


Parallel Assignment in Ruby

def hoge
  return 1, 2
end

a, b = hoge
# a=>1, b=>2

Examples in Ruby

a, b = [1, 2]
# a=>1, b=>2
a, b, c = [1, 2]
# a=>1, b=>2, c=>nil
a, b = [1, 2, 3]
# a=>1, b=>2
a, *b = [1, 2, 3]
# a=>1, b=>[2, 3]
*a, b = [1, 2, 3]
# a=>[1, 2], b=>3
*, b = [1, 2, 3]
# b=>3

Arrayのみが対象 in Ruby

Hash から Parallel Assignment したりはできない

h = { a: 1, b: 2 }
a, b = h
# a=>{a:1, b:2}, b=>nil

Destructuring assignment in ES6

Array destructuring assignment

[a, b] = [1, 2];
// a=>1, b=>2
[, b] = [1, 2, 3];
// b=>2
[, ...b] = [1, 2, 3];
// b=>[2, 3]

Object destructuring in ES6

  • 名前が一致していること
var o = { a: 1, b: 2 };
var {a, b} = o;
// a=>1, b=>2
var {x, y} = o;
// x=>undefined, y=>undefined
var o = { a: 1, b: 2 };
var {a: alpha, b: bravo} = o;
// alpha=>1, bravo=>2
  • importで重宝したりするみたい
import {foo, bar} from "module"

Destructuring Declarations in Kotlin

stdlibで定義されているPairを使った例

data class Pair<A, B>(first: A, second: B)

val p = Pair(first = 1, second = 2)
// p.first=>1, p.second=2
val (a, b) = p
// a=>1, b=>1

蛇足: AndroidにもPairクラスがあり、まあまあ使われている。

package android.util;

public class Pair<F, S> {
  public final F first;
  public final S second;
}

別に destructure がないと困ることもないよね?

例: 値を返すが、失敗時はエラーを、キャンセルされた場合はその旨を、戻り値で返したい。

public sealed class Result {
    data class Ok(val data: String): Result()
    data class Error(val error: Error): Result()
    object Canceled: Result()
}

val result = doSomething()
when (result) {
    is Result.Ok -> print(result.data)
    is Result.Error -> result.error.printStackTrace()
    is Result.Canceled -> print("canceled")
}

あくまで Declaration

var a: Int
var b: Int
(a, b) = Pair(first = 1, second = 2) // compile error

宣言時以外には使用できない。


destructuring は componentN() 関数の呼び出し

val p = Pair(1, 2)
val (a, b) = p
val p = Pair(1, 2)
val a = p.component1()
val b = p.component2()

data class(この例だとPairクラス)が、componentN()関数を自動的に定義するため、このようなことが可能。


定義順が変更されると、当然壊れる

data class Person(
  var name: String,
  var age: Int
)

val p = Person(name = "yuki.terai", age = 17)
val (name, age) = p
// name=>"yuki.terai"

上記を、data classでのプロパティ宣言順だけ変えても、コンパイルは通る。

data class Person(
  var age: Int,
  var name: String
)

val p = Person(name = "yuki.terai", age = 17)
val (name, age) = p
// name=>17

通常のclassでも可能

class Hoge(
  var foo: Int,
  var bar: Int
) {
  operator fun component1() = foo
  operator fun component2() = bar
  operator fun component3() = "baz"
}

var (a, b, c) = Hoge(1, 2)
// a=>1, b=>2, c="baz"
  • componentN() 関数が定義されていればコンパイルが通る。
  • 演算子を実装するためのoperator関数として、言語仕様でpredefinedされている。

predefined ということはNは無限ではない?

data class Hoge(
    var first: Int,
    var second: Int,
    var third: Int,
    var fourth: Int,
    var fifth: Int,
    var sixth: Int,
    var seventh: Int,
    var eighth: Int,
    var ninth: Int,
    var tenth: Int
)

val hoge = Hoge(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val (a, b, c, d, e, f, g, i, j, k) = hoge
// k=>10

arrayだとどうなるのか

val list = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val (a, b, c, d, e, f, g, i, j, k) = list
  • Compile Errorとなるorz
    • Destructuring declaration initializer of type List must have a 'component6()' function
  • collectionでは、component5() までしか定義されていないっぽい?

rest in object 的な宣言ができない

var (a, _) = arrayOf(1, 2, 3)
// a=>1

上記のように _ を使ったり定義しなかったりで捨てることはできるが、残りをarrayで受け取る手段がない

fun concat(vararg strings: Int): String {
  return strings.joinToString()
}

val a = arrayOf("hello", "world")
val str = concat(*a)

可変長引数 vararg のために展開する spread operator はあるので、destructuringでも同様にやってはどうかというアイディアはある。

var (a, *x) = arrayOf(1, 2, 3)
// !! Compile error for now

まとめ

  • Kotlin の Destructuring Declarations は微妙な点も多く、いまいち使い所がわからない。
  • Kotlin 1.3 現在だが、今後に期待なのだろうか?
4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1