Kotlin在伴侣对象中使用Apply引发意外错误

MrP*_*low 5 kotlin

假设我想A通过从类B中复制值来实例化类的对象,这是常见的做法,例如,在映射DTO时。为了在Java或Groovy中实现此目的,我将在适当的DTO上创建带有签名的静态方法fromB(A a),然后a.val = b.val...在Java中或a.with { val = b.val... }在Groovy中使用复制值。

在Kotlin中,我注意到它instance.apply{}与Groovy的相似之处with在于,它允许我直接访问对象变量,而无需不断引用对象本身,因为该引用似乎隐含在闭包中。

但是,在伴侣对象中使用Apply时遇到了一个奇怪的意外错误。如果我A().apply {}在A的伴随对象的函数中使用,Expression is inaccessible from a nested class 'Companion', use 'inner' keyword to make the class inner则会收到一个奇怪的错误,因为我直接在对象的实例上调用apply,因此希望我始终可以访问它的公共属性。更不用说似乎不能将伴随对象设置为inner错误对象,因此错误消息中的建议并不是很有帮助。

这是完整的示例代码:

fun main(args: Array<String>) {
    val b = B("Hello", "World")
    val a = A.fromB(b)

    print("$a.value1 $a.value2")
}


class A() {
    var value1: String? = null
    var value2: String? = null

    companion object {
        //This fails with "Expression is inaccessible from a nested class 'Companion', use 'inner' keyword to make the class inner"
        fun fromB(b: B): A {
            return A().apply {
                value1 = b.value3
                value2 = b.value4
            }
        }
    }
}

class B(val value3: String, val value4: String) {}

//This works
fun bToA(b: B): A {
    return A().apply {
                value1 = b.value3
                value2 = b.value4
            }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?我究竟做错了什么?

mfu*_*n26 4

这对我来说看起来像是一个错误。apply可能与内联函数(例如)和伴随对象有关。我建议搜索JetBrains Bug & Issue Tracker,如果您没有找到类似的内容,请创建一个新问题。

与此同时,我看到了一些替代方案:

  1. 使用this(不理想):

    fun fromB(b: B): A {
        return A().apply {
            this.value1 = b.value3
            this.value2 = b.value4
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 移动value1and value2toA的主构造函数并更改fromB(B)为使用命名参数(这仍然允许您定义默认值、在复制时跳过属性等):

    class A(var value1: String? = null, var value2: String? = null) {
        companion object {
            fun fromB(b: B): A {
                return A(
                        value1 = b.value3,
                        value2 = b.value4
                )
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    更新:除了上述之外,您还可以b使用with

    fun fromB(b: B) = with(b) {
        A(
                value1 = value3,
                value2 = value4
        )
    }
    
    Run Code Online (Sandbox Code Playgroud)