簡體   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