【问题标题】:Kotlin Function Literal with Any Receiver type具有任何接收器类型的 Kotlin 函数文字
【发布时间】:2020-04-13 19:34:43
【问题描述】:

我试图让 kotlin 接受一个接口类型作为函数的接收者,但我收到一个编译错误,提示类型不匹配。

这是一个例子:

interface Foo

class Bar : Foo

fun main() {
    val l = initBar {

    }

    initFoo(l) // Doesnt work compile error: Type mismatch.
                                                //Required:
                                                //  Foo.() → Unit
                                                //Found:
                                                //  Bar.() → Unit
}

fun initBar(init: Bar.() -> Unit) = init


fun initFoo(init: Foo.() -> Unit) = Unit

我从这段代码中得到以下编译错误

Type mismatch.
Required:
Foo.() → Unit
Found:
Bar.() → Unit

有没有办法让 initFoo 函数接受任何实现 Foo 而不进行强制转换的接收者对象?

谢谢。

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    为其使用泛型类型:

    fun <T: Foo> initFoo(init: T.() -> Unit) = Unit
    

    请注意,这限制了您可以在函数内使用它执行的操作。由于您接受可以在特定类型上调用的函数,因此您不能在任何 Foo 上调用传入的 lambda。

    fun <T: Foo> initFoo(init: T.() -> Unit) {
        val someFoo = object: Foo {}
        someFoo.init() // ERROR (type mismatch)
    }
    

    这是因为,例如,您的 Bar.() -&gt; Unit 函数可能正在使用 Bar 的属性和函数,而这些属性和函数不一定是任意 Foo 的一部分。

    【讨论】:

    • 我试图避免使用泛型类型/强制转换来最小化运行时开销。我认为使用 Interface 实现类型或 Any 将允许此代码工作,但我想不会。
    • 泛型不会增加开销,除非类型是原始类型,然后必须对其进行包装。使用 lambda 的开销比强制转换高出几个数量级。除非您一次调用此函数数万次,否则无需担心。
    • 会调用很多。 lambda 被缓存并存储在内存中,因此在启动后运行时几乎不会有任何开销。现在它每次调用其中一个 lambda 时都会强制转换,我只是希望我可以避免这种情况。我想如果没有其他选择,我将不得不重新使用泛型。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多