【问题标题】:Kotlin - Is there a way of defining an explicit scope of a function with receiver defined in companion object?Kotlin - 有没有办法用伴随对象中定义的接收器来定义函数的显式范围?
【发布时间】:2021-02-12 01:51:40
【问题描述】:

假设您有以下代码:

interface SomeClient {

    fun isValid(value: String): Boolean
}

class SomeData private constructor(
    val value: String
) {

    companion object {

        fun SomeClient.create(value: String): SomeData? =
            if (isValid(value)) {
                SomeData(value)
            } else {
                null
            }
    }
}

class SomeOtherData private constructor(
    val otherValue: String
) {

    companion object {

        fun SomeClient.create(value: String): SomeOtherData? =
            if (isValid(value)) {
                SomeOtherData(value)
            } else {
                null
            }
    }
}

class SomeUseCase(
    someClient: SomeClient
) : SomeClient by someClient {

    fun run() {
        val someData = SomeData.create("hello")
        val someOtherData = SomeOtherData.create("wassup")
    }
}

整个意图是提供一个静态工厂方法来创建一个有效的值对象(SomeDataSomeOtherData),但验证逻辑包括一些 IO 操作。因此,我想将调用 create 方法的范围限制为实现 SomeClient 的类。

这里的问题是编译器无法解析SomeUseCase#run内部的伴随对象方法(SomeData#createSomeOtherData#create),它抱怨接收器不正确。

我当然可以这样做

class SomeUseCase {
    fun run() {
        val someData = this.createSomeData(...)
        val someOtherData = this.createSomeOtherData(...)
    }
}

并相应地重命名创建方法,但我想保留名称,所以它是SomeData.create,而不是SomeData.createSomeData

有没有办法做到这一点?这有意义吗?

【问题讨论】:

    标签: kotlin kotlin-extension


    【解决方案1】:

    当您在SomeData 伴随对象中写入fun SomeClient.create(value: String) 时,您不是为伴随对象定义create 方法,而是在伴随对象的范围内为SomeClient 定义extension function

    如果你重写它使其成为伴生对象的方法,你会看到isValid()调用没有接收者,所以它需要作为参数传递在那里:

    class SomeData private constructor(val value: String) {
        companion object {
            fun create(value: String, validator: SomeClient): SomeData? =
                if (validator.isValid(value)) SomeData(value) else null
        }
    }
    

    之后就可以像这样在SomeClient的范围内调用:

    val someData = SomeData.create("hello", this)
    

    每次创建调用都重复this有点麻烦,所以你可以在SomeClient接口范围内为SomeData伴生对象定义一个扩展函数:

    interface SomeClient {
        fun isValid(value: String): Boolean
    
        fun SomeData.Companion.create(value: String) = create(value, this@SomeClient)
    }
    

    之后,它可以在SomeClient的范围内以所需的方式调用:

    val someData = SomeData.create("hello")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-11
      • 1970-01-01
      • 1970-01-01
      • 2021-10-10
      • 2021-07-08
      • 2023-02-15
      • 2023-03-21
      • 2021-10-30
      相关资源
      最近更新 更多