hiro99ma blog

何か技術的なこと

kotlin の enum

2024/10/10

C/C++ には enumがある。
私がやりがちなこれだが、他の言語では仕様としてできないことが多い。

#include <stdio.h>

int main(void)
{
    enum {
        First, Second, Third,
    } part = First;
    printf("part=%d\n", part);
    part++;
    printf("part=%d\n", part);
    return 0;
}

C/C++ は enum は整数型扱いになるので計算に使うことができる。対応できる一番小さい整数型にするとかだったか。
あと、デバッガでenum型扱いにしてもらえるので値がちょっと見やすい。

それに慣れていたので思うところはないのだが、列挙型が計算できるってなんなのよ、と言われれば確かにそういう気もする。
Go言語にはないし、TypeScriptだと使わない方がよいとかあるし。
Kotlin にも enum があるが同様に整数型扱いではない。


Kotlin の列挙型は enum class という使い方になる。

これは OK だ。
出力は「First」である。

enum class Status {
    First, Second, Third,
}

fun main() {
    var status: Status = Status.First
    println("$status")
}

ordinalを付けると順番の整数値が取得できる。
こうすると出力は「1」である。

fun main() {
    var status: Status = Status.Second
    println("${status.ordinal}")
}

プライマリーコンストラクタにプロパティを付けて値付きで定義することもできる。
in enum型.entriesenumValueOf(文字列) のようなちょっと特殊な使い方ができる。 しかし status にインクリメントしたり計算結果の代入はできない。

数値として使いたいなら数値型を使えばよいのだ。
それはわかっているのだが、状態を enum型にして、次に進めるときは++して、と考えてしまうのだ。呪いのようなものか。

あきらめて enum class で計算無しに使うか、整数型にして const valを使って #define的なものを用意するのか?


整数値からenum値に変換する関数を持たせることで対応する例があった。

How do I create an enum from an Int in Kotlin? - Stack Overflow

enum class Types(val value: Int) {
    FOO(1),
    BAR(2),
    FOO_BAR(3);

    companion object {
        fun fromInt(value: Int) = Types.values().first { it.value == value }
    }
}

fun main() {
    var t = Types.fromInt(1)
    println("t=${t}")
    t = Types.fromInt(t.value+1)
    println("t=${t}")
}

fromInt()は何をやってるんでしょうね。。。
first() は集合型の先頭要素に関するものだが、itとか使っているから後置ラムダ式というやつだろう。

inline fun <T> Array<out T>.first(
    predicate: (T) -> Boolean
): T

その実装はこちらで、イテレータでぐるぐる回してラムダ式の中に書いた結果がtrueであればそのときのTをそのまま返す。

public inline fun <T> Array<out T>.first(predicate: (T) -> Boolean): T {
    for (element in this) if (predicate(element)) return element
    throw NoSuchElementException("Array contains no element matching the predicate.")
}

なるほどねぇ。
forでぐるぐる回せばできるとは思ったが、まあそれしかないわな。
ちなみに対応する値を引数に与えない場合は NoSuchElementException が発生する。

ただ、1行で書かれているから気付きにくいが、大した処理ではないとはいえループで回っている。
これをわざわざループで回して処理したいかと私は NO なのだが、一般的にはどうなんだろう。

< Top page