LoginSignup
6
4

More than 5 years have passed since last update.

Kotlin: DslMarker

Last updated at Posted at 2018-06-28

DSL の書き方

Kotlin で DSL を書く場合のサンプルコードです。

class A {
    var valueA: String? = null
    var b: B? = null

    fun b(init: B.() -> Unit): B {
        val b = B()
        b.init()
        this.b = b
        return b
    }
}

class B {
    var valueB: String? = null
    var c: C? = null

    fun c(init: C.() -> Unit): C {
        val c = C()
        c.init()
        this.c = c
        return c
    }
}

class C {
    var valueC: String? = null
}

fun a(init: A.() -> Unit): A {
    val a = A()
    a.init()
    return a
}

このように書くと、次のように クラスA のオブジェクトを作ることができます。

a {
    valueA = "A"
    b {
        valueB = "B"
        c {
            valueC = "C"
        }
    }
}

@DslMarker

上のサンプルでは、次のようなコードも書けてしまいます。

a {
    valueA = "A"
    b {
        valueB = "B"
        c {
            valueA = "A"
            valueC = "C"
        }
        b {
            valueA = "A"
            valueB = "B"
            b {
                valueB = "B"
            }
        }
    }
}

具体的な問題項目は次の通りです。

  • B, C を定義するブロックの中で A の属性が代入されている。
  • B を定義するブロックの中で、さらに B を定義する関数とそのブロックが記述されている。
    • B は B をプロパティにもたないのに

これを Kotlin 1.1 から導入されているアノテーション @DslMarker が解決します。 @DslMarker はDSLを作成する際の、スコープを制御するために使えるアノテーションです。 このアノテーションは、アノテーションクラスに付与します。

@DslMarker を付けたアノテーションクラス(DslMarkerTest)を作成し、 DSLを生成するクラスに付与します。 クラス A, B にアノテーションDslMarkerTestを付与します。

@DslMarker
annotation class DslMarkerTest

@DslMarkerTest
class A { ... }

@DslMarkerTest
class B { ... }

class C { ... }

こうすると、上のコードがエラーになります。

(この記事は拙ブログから抜粋・編集したものです。)

6
4
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
6
4