繁体   English   中英

Kotlin:相互指派

[英]Kotlin: Mutual assignments

我想设置两个值,彼此保持不可变的引用。 例:

data class Person(val other: Person)
val jack = Person(jill), jill = Person(jack)   // doesn't compile

注意: lateinit似乎不适用于数据类主构造函数。

有任何想法吗?

你可以逃避这样的事情:

class Person() {
    private var _other: Person? = null

    private constructor(_other: Person? = null) : this() {
        this._other = _other
    }

    val other: Person
        get() {
            if (_other == null) {
                _other = Person(this)
            }
            return _other ?: throw AssertionError("Set to null by another thread")
        }
}

然后你就能做到:

val jack = Person()
val jill = jack.other

在这里使用data class不会出于多种原因

  1. 首先是因为data class不能有空构造函数。

  2. 即使这不是问题,生成的方法最终会产生循环依赖,并且会在运行时因java.lang.StackOverflowError而失败。 所以你必须覆盖toStringequals等,这首先打破了使用data class 的目的

这是诀窍(注意,这真的是一个技巧,你需要一个很好的理由在实际代码中使用它)。

不幸的是,它不适用于数据类,因为它们似乎可以抵御这种黑客攻击。

但是如果你有java-stile类,你可以使用两件事:

  1. 你可以在构造函数中初始化val (与java中的final相同)
  2. 您可以访问this构造函数中的(并且可能泄漏到外部,如果你真的想)

这意味着您可以在第一个人的构造函数创建另一个Person ,并在构造函数完成之前完成两个类的创建。

再一次:暴露this就像我在下面做的那样是一个主意。 otherFactory ,它的参数只是半初始化。 这可能会导致令人讨厌的错误,特别是如果您尝试在多线程环境中发布此类引用。

更安全的方法是在第一个Person的构造函数内创建两个Persons(您需要提供两个实体的字段作为参数)。 它更安全,因为您可以控制使用半初始化this引用的代码。

class Person {
    val name: String
    val other: Person

    constructor(name: String, other: Person) {
        this.name = name
        this.other = other
    }

    // !! not very safe !!
    constructor(name: String, otherFactory: (Person) -> Person) {
        this.other = otherFactory(this)
        this.name = name
    }

    // a bit safer
    constructor(name: String, otherName: String) {
        this.other = Person(otherName, this)
        this.name = name
    }
}

val person1 = Person("first") {
    Person("second", it)
}

val person2 = person1.other

print(person1.name) // first
print(person2.name) // second

val person3 = Person("third", "fourth")
val person4 = person3.other

print(person3.name)
print(person4.name)

感谢大家的建议。 我提出了一个替代方案,并希望听到您的见解:

open class Person {
  open val other: Person by lazy { Person2(this) }
  class Person2(override val other: Person): Person()
}

val jack = Person()
val jill = jack.other

在这里,我们没有一个人懒洋洋地实例化的其他需求,使用实现内部子类other不同的(也就是说,它只是给它直接在它的构造函数)。

最受欢迎的想法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM