Kotlin - 限制扩展方法范围

问题描述 投票:4回答:2

有没有办法限制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 { }电话?

scope dsl kotlin
2个回答
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

编辑:修好我的例子后,它变小了。对于一个类有一个虚函数,毕竟它不是那么多的样板。


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

因此,最后一次中间呼叫不再可编译。

© www.soinside.com 2019 - 2024. All rights reserved.