概要
- KotlinはJava同様Enumに振る舞い(メソッド)を持たせることができる
- Groovyから振る舞いを持ったEnum要素を直接参照するとエラーになる
- Direct field access operator(
@
)経由で参照すればOK - EnumのValueOfでも参照できる
振る舞いを持たないEnumはうまくいく
enum class Shape { CIRCLE, TRIANGLE, SQUARE, } // Enumをフィールドに持つクラス class Foo(val shape: Shape)
class FooTest extends Specification { def "KotlinのEnumを使ったテスト"() { given: def shape = Shape.CIRCLE when: def actual = new Foo(shape) then: actual.shape == Shape.CIRCLE } }
振る舞いをもたせるとエラーになる
// 振る舞いを持ったEnum enum class Shape { CIRCLE { override fun sign(): String = "○" }, TRIANGLE { override fun sign(): String = "△" }, SQUARE { override fun sign(): String = "□" }; abstract fun sign(): String } class Foo(val name: String, val shape: Shape)
GroovyRuntimeExceptionが発生してしまう。
groovy.lang.GroovyRuntimeException: Could not find matching constructor for: Foo(java.lang.Class)
どうも振る舞いをもたせるとClassになるようだ。
コンパイル結果を見るとたしかにclassファイルができている。
- Shape$CIRCLE.class
- Shape$SQUARE.class
- Shape$TRIANGLE.class
メソッドも呼び出せない
def "KotlinのEnumメソッドを呼び出すテスト"() { expect: Shape.CIRCLE.sign() == "○" }
MissingMethodExceptionが発生してしまう。
Caused by: groovy.lang.MissingMethodException: No signature of method: static Shape$CIRCLE.sign() is applicable for argument types: () values: []
Enumのインスタンス経由で呼び出す
Direct field access operator(@
)を使って、要素のインスタンスを使うようにするとうまくいきます。
class FooTest extends Specification { def "KotlinのEnumを使ったテスト"() { given: def shape = Shape.@CIRCLE when: def actual = new Foo(shape) then: actual.shape == Shape.@CIRCLE } def "KotlinのEnumメソッドを呼び出すテスト"() { expect: Shape.@CIRCLE.sign() == "○" } }
valueOf経由で呼び出す
valueOfを使うようにしてもOKです。
class FooTest extends Specification { def "KotlinのEnumを使ったテスト"() { given: def shape = Shape.valueOf('CIRCLE') when: def actual = new Foo(shape) then: actual.shape == Shape.valueOf('CIRCLE') } def "KotlinのEnumメソッドを呼び出すテスト"() { expect: Shape.valueOf('CIRCLE').sign() == "○" } }