Kotlin使用适用于伴侣对象会引发意外错误

比方说,我想通过复制类B值来实例化类A的一个对象,例如,映射DTO的时候这是很常见的做法。 要在Java或Groovy中实现这一点,我会创建一个静态方法在相应的DTO上签名fromB(A a) ,然后用a.val = b.val...在Java中复制值或使用a.with { val = b.val... }在Groovy中。

在Kotlin中,我注意到instance.apply{}与Groovy非常相似,它允许我直接访问对象变量,而不必一直引用对象本身,因为引用似乎隐含在闭包中。

然而,当在同伴对象中使用apply时,我遇到了一个奇怪的和意想不到的错误。 如果我在A的伴侣对象的函数中使用A().apply {} ,我得到一个错误Expression is inaccessible from a nested class 'Companion', use 'inner' keyword to make the class inner变得很奇怪,因为我打电话直接应用于对象的一个​​实例,并因此期望我应该总是能够访问它的公共属性。 更何况,似乎伴侣对象不能被设置为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 } } 

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

这看起来像是一个bug。 可能与内联函数(如apply )和伴随对象有关。 我建议您搜索JetBrains Bug&Issue Tracker ,如果您没有发现与此类似的内容,则会产生新问题。

在此期间,我看到一些替代方案:

  1. 使用this (不理想):

     fun fromB(b: B): A { return A().apply { this.value1 = b.value3 this.value2 = b.value4 } } 
  2. value1value2移到A的主构造器,并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 ) } } } 

    更新:除了上面的你可以使用bwith

     fun fromB(b: B) = with(b) { A( value1 = value3, value2 = value4 ) } 

@MrPlow

我认为这是更直接的做法,你想要什么:

 fun B.toA(): A { val self = this; return A().apply { value1 = self.value3 value2 = self.value4 } } 

与你的例子比较:

 val b = B("Hello", "World") val a = A.fromB(b) // vs val a = b.toA();