05. enum 編
今回は、 LuneScript の enum 値について説明します。
enum
LuneScript の enum は、値の集合に名前を付けて管理することが出来ます。
enum として扱える値の型は次の通りです。
- int
- real
- str
1 つの enum の値域は、複数の値から定義できますが、 値の型は統一する必要があります。
つまり、 int の値を持つ enum は、 real や str の値は定義できません。
定義方法
enum は次のように定義します。
// @lnsFront: ok
enum TestEnum {
val0,
val1,
val2,
}
print( TestEnum.val0, TestEnum.val1, TestEnum.val2 ); // 0, 1, 2
この例では、 val0, val1, val2 を定義し、それぞれ 0, 1, 2 となります。
enum の値を指定する場合は、次のように定義します。
// @lnsFront: ok
enum TestEnum {
val0 = 10,
val1,
val2 = 20,
}
print( TestEnum.val0, TestEnum.val1, TestEnum.val2 ); // 10, 11, 20
enum の値を省略した場合、次に従って値を assign します。
- 直前の enum 値に 1 を加算した値を assign する。
- 先頭の enum 値は 0
なお、 enum 値に文字列を assign する場合、値を省略することは出来ません。
// @lnsFront: ok
enum TestEnum {
val0 = "abc",
val1 = "def",
val2 = "ghi",
}
print( TestEnum.val0, TestEnum.val1, TestEnum.val2 ); // abc def ghi
enum 値に設定する値には、式を指定出来ます。 ただし、この式は immediate な値だけを使用している必要があります。
例えば次のような場合、
// @lnsFront: error
fn func(): int {
return 100;
}
enum TestEnum {
val0,
val1 = val0 + 10, // 10
val2 = func(), // error
}
val = val0 + 10
は、 immediate な値を利用しているため指定可能ですが、
val2 = func()
は、 immediate な値ではないためエラーとなります。
使用方法
定義した enum は、次のように型として利用できます。
// @lnsFront: ok
enum TestEnum {
val0,
val1,
val2,
}
fn func( val:TestEnum ): int {
return val + 100;
}
print( func( TestEnum.val1 ) ); // 101
ここで func()
の引数 val は TestEnum 型です。
これにより、 func()
の引数 val は単なる int ではなく、
値域が制限された int とすることが出来ます。
enum 値を指定する場合は、
TestEnum.val
のように enum 型シンボル.enum 値シンボル
となります。
省略指定
基本的に enum 値を指定するには、
enum 型シンボル.enum 値シンボル
となりますが、
代入先の型が enum 型であることが分っている場合、
enum 型シンボル
を省略することが出来ます。
例えば次の場合、 func()
の引数は TestEnum 型であることが分っているので、
TestEnum.val1 ではなく、 .val1 として指定できます。
// @lnsFront: ok
enum TestEnum {
val0,
val1,
val2,
}
fn func( val:TestEnum ): int {
return val + 100;
}
print( func( .val1 ) ); // 101
なお、 外部モジュールで定義されている enum 型を省略指定する場合、 その外部モジュールを import している必要があります。
import については後日説明します。
enum 値の変換
enum 値は、enum 値として以外に、定義した値としても利用できます。
これは上の例の val + 100 を見ると分かると思いますが、
val は TestEnum で定義した enum 値ですが、それは 0, 1, 2 のいずれかでもあります。
(上の例では val1 を渡しているので 1 になる)。
よって val + 100
は、 1 + 100 となり結果的に 101 となります。
一方で次の例を見てください。
// @lnsFront: error
enum TestEnum {
val0,
val1,
val2,
}
fn func( val:TestEnum ): int {
return val + 100;
}
let val = 1;
func( val ); // error
この例の func( val )
はエラーとなります。
この場合 val は 1 で、 TestEnum において val1 が 1 となりますが、 val の型が int であり、 TestEnum とは型が異なるためエラーとなります。
enum 値に assign している型の値から、
対応する enum 値に変換するには、次のように _from()
関数を利用します。
// @lnsFront: ok
enum TestEnum {
val0,
val1,
val2,
}
fn func( val:TestEnum ): int {
return val + 100;
}
let val = 1;
func( unwrap TestEnum._from( val ) );
ここで func( unwrap TestEnum._from( val ) )
は、
TestEnum._from()
によって val に対応する TestEnum の enum 値 TestEnum.val1 を取得し、
それを func()
に渡しています。
unwrap については後日説明します。
enum 値名
enum 値はシンボルに値を assign します。
enum 値は $_txt によって、このシンボル名を動的に取得できます。
例えば次の場合、TestEnum.val1 が出力されます。
// @lnsFront: ok
enum TestEnum {
val0,
val1,
val2,
}
fn func( val:TestEnum ) {
print( val.$_txt );
}
func( .val1 ); // TestEnum.val1
$_txt
によって、 enum 値のシンボル名を取得しています。
$ については後述しますが、関数呼び出しのシンタックスシュガーです。
$_txt の注意点
$_txt
には次の注意点があります。
「同値の enum 値が複数存在する場合、 $_txt がどの enum 値のシンボル名を返すか未定義」
例えば次の場合、 print()
が TestEnum.val1
, TestEnum.val2
のどれを出力するかは未定義です。
// @lnsFront: ok
enum TestEnum {
val0,
val1 = 10,
val2 = 10,
}
fn func( val:TestEnum ) {
print( val.$_txt );
}
func( .val1 ); // TestEnum.???
また、 $_txt によって得られる文字列フォーマットは将来変更する可能性があります。
$_txt
は、ログ出力目的の使用に制限し、
$_txt
の結果によって処理を切り替えるようなコードを書かないでください。
全 enum 値リスト
$_allList で、enum が定義している全 enum のリストを取得できます。
例えば次のコードの場合、
// @lnsFront: ok
enum TestEnum {
val0,
val1,
val2,
}
foreach val in TestEnum.$_allList {
print( val.$_txt );
}
次を出力します。
TestEnum.val0
TestEnum.val1
TestEnum.val2
代数的データ型
enum 型は、 int, real, str のいずれか一種類の型をグルーピングして、 値域を制限できますが、複数の型をグルーピングすることは出来ません。 代数的データ型は enum 型をより一般的にしたもので、 int, real, str に限らず全ての型をグルーピングすることが出来ます。
詳しくは次の記事で説明しています。
まとめ
enum を利用することで、値域を簡単に定義することが出来、 enum を楽に扱うイマドキな手段を提供しています。
次回は、変数について説明します。