Kotlin - 限制扩展方法范围

时间:2016-05-02 22:47:51

标签: scope dsl kotlin

有没有办法限制DSL中的扩展方法?

假设我有这样的类结构:

class Outer {
    fun middle(op: Middle.() -> Unit): Middle {
        val middle = Middle()
        middle.op()
        return middle
    }
}

class Middle {
    fun inner(op: Inner.() -> Unit): Inner {
        val inner = Inner()
        inner.op()
        return inner
    }
}

class Inner

fun outer(op: Outer.() -> Unit): Outer {
    val outer = Outer()
    outer.op()
    return outer
}
然后我可以像这样创建一个调用:

outer {
    middle {
        inner {
            middle { }  // Here is the problem
        }
    }
}

我的问题是,标记为middle { }的通话令人困惑,因为当Middle看起来正在添加Outer时,会向Inner添加middle { }。 / p>

有没有办法不允许String[] DoctorEp = new String[107]; void DoctorDec() { DoctorEp[0] = "rose"; DoctorEp[1] = "the end of the world"; DoctorEp[2] = "the unquiet dead"; DoctorEp[3] = "aliens of london"; DoctorEp[4] = "world war three"; DoctorEp[5] = "dalek"; DoctorEp[6] = "the long game"; DoctorEp[7] = "father's day"; DoctorEp[8] = "the empty child"; DoctorEp[9] = "the doctor dances"; DoctorEp[10] = "boom town"; } 来电?

2 个答案:

答案 0 :(得分:8)

您可以使用deprecated的解决方法:

class Outer {
    fun middle(op: Middle.() -> Unit): Middle {...}

    @Deprecated("can not be used inside a Outer block", level = DeprecationLevel.ERROR)
    fun outer(op: Outer.() -> Unit): Outer = TODO()
}

class Middle {
    fun inner(op: Inner.() -> Unit): Inner {...}

    @Deprecated("can not be used inside a Middle block", level = DeprecationLevel.ERROR)
    fun middle(op: Middle.() -> Unit): Middle = TODO()
}

class Inner {
    @Deprecated("can not be used inside a Inner block", level = DeprecationLevel.ERROR)
    fun inner(op: Inner.() -> Unit): Inner = TODO()
}

现在编译器会给你一个错误,IDE在完成时不会建议错误的函数:

outer {
    middle {
        inner {
            middle { }  // error
        }
    }
}

但你真的不应该为大型DSL做这件事。最好像@KirillRakhman建议的那样等待https://youtrack.jetbrains.com/issue/KT-11551

修改:我修复了我的示例后,它变得更小了。对于一个类有一个虚拟函数,它毕竟不是那么多的样板。

答案 1 :(得分:0)

限制范围的官方方法是DslMarker。 在某些情况下(例如,当您需要注释Java源代码时)它无济于事-在这里使用@Deprecated。但是请先尝试DslMarker

@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class Scope

@Scope
class Outer {
    fun middle(op: Middle.() -> Unit): Middle { /**/ }
}

@Scope
class Middle {
    fun inner(op: Inner.() -> Unit): Inner {/**/ }
}

class Inner

因此,最后一个 middle 调用不再可编译。