【问题标题】:Kotlin - Restrict extension method scopeKotlin - 限制扩展方法范围
【发布时间】:2016-05-02 22:47:50
【问题描述】:

有没有办法限制 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 { } 调用令人困惑,因为它在看起来像是添加到Inner 时将Middle 添加到Outer

有没有办法不允许middle { } 调用?

【问题讨论】:

标签: scope dsl kotlin


【解决方案1】:

您可以使用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

编辑:在我修复了我的示例后,它变得更小了。对于一个类来说只有一个虚拟函数,它毕竟不是样板文件。

【讨论】:

  • @KirillRakhman 请查看编辑。现在对于 n 个类,它只有 n 个虚拟函数,而不是 (n^2)/2。并且感谢level 参数,这些弃用不是警告,而是错误。有了这个,我看不到像 KT-11551 这样的用例语言级别功能的任何好处
【解决方案2】:

限制范围的官方方法是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 调用不再可编译。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-03
    • 2017-04-17
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 1970-01-01
    • 2020-10-28
    相关资源
    最近更新 更多