Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Kotlin 科特林:相互分配_Kotlin_Immutability - Fatal编程技术网

Kotlin 科特林:相互分配

Kotlin 科特林:相互分配,kotlin,immutability,Kotlin,Immutability,我想设置两个值,它们彼此保持不可变的引用。例如: 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

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

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
由于多种原因,在此处使用
数据类不起作用

  • 首先是因为
    数据类
    不能有空构造函数

  • 即使这不是问题,生成的方法最终也会有一个循环依赖关系,并在运行时使用
    java.lang.StackOverflowerError
    失败。因此,您必须覆盖
    到字符串
    等于
    ,等等。哪种首先违背了使用
    数据类的目的

  • 这里是诀窍(注意,这确实是一个诀窍,在实际代码中使用它需要一个很好的理由)

    不幸的是,它对数据类不起作用,因为它们似乎受到了这种黑客攻击的保护

    但是,如果您有java stile类,您可以使用两个优势:

  • 您可以在构造函数中初始化
    val
    s(与java中的
    final
    相同)
  • 您可以在构造函数内部访问此(如果确实需要,您可以将其泄漏到外部)
  • 这意味着您可以在第一个人的构造函数中创建另一个人,并在构造函数完成之前完成两个类的创建

    再一次:像我在下面所做的那样暴露
    这个
    是一个糟糕的想法。调用
    otherFactory
    时,其参数仅初始化了一半。这可能会导致严重的错误,尤其是当您试图在多线程环境中发布此类引用时

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

    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
    (也就是说,它只是直接在其构造函数中给出)


    思想最受欢迎。

    可能是空值var。我真的希望避免可空变量。应用程序的其余部分在设置时应该考虑这个属性是不可变的。这是一个循环依赖问题:要创建杰克,我需要JIL,这又需要杰克等等。@ M0SKIT0纠正。有什么想法吗?@CSJ我想我没有正确解释自己。你想做的事情在逻辑上是不可能的(更严格地说,它需要无限的时间),除非你想放松你的条件。可能是
    lazy
    lateinit
    ?我在这里用
    lateinit
    写的。虽然我可以将
    Person?
    类型转换为
    Person
    ,但我觉得它不再可读了。更重要的是,我不确定当有并发访问时,
    isInitialized
    检查会发生什么。