Kotlin在伴随对象中使用apply会引发意外错误

时间:2015-12-08 19:10:58

标签: kotlin

让我们说我想通过复制类A中的值来实例化类B的对象,这是一种常见做法,例如,映射DTO&#39 ; S。要在Java或Groovy中实现此目的,我需要在相应的DTO上创建一个静态方法,其签名为fromB(A a),然后使用Java中的a.val = b.val...或使用a.with { val = b.val... }复制值。 Groovy的。

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

但是,当在随播对象中使用apply时,我遇到了一个奇怪且意外的错误。如果我在A&#39伴随对象的函数中使用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
            }
}

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

2 个答案:

答案 0 :(得分:4)

对我来说这看起来像个错误。可能与内联函数(例如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
        )
    }
    

答案 1 :(得分:1)

@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();