问题
In Kotlin, say I have data class A (val f: B)
and data class B (val f: A)
. I want to initialize local var a: A
and var b: B
such that a.f
is b
and b.f
is a
. A.f
and B.f
must remain vals. Is this circular instantiation possible?
data class A(val f: B)
data class B(val f: A)
fun foo() {
var a: A
var b: B
// instantiate a and b here with a.f == b and b.f == a ??
}
回答1:
Not exactly what you want but should work:
interface A {
val f: B
}
interface B {
val f: A
}
data class AImpl(override var f: B) : A
data class BImpl(override var f: A) : B
fun <T> uninitialized(): T = null as T
fun foo() {
var aImpl = AImpl(uninitialized())
var bImpl = BImpl(aImpl)
aImpl.f = bImpl
val a: A = aImpl
val b: B = bImpl
}
If you do not care about data class properties being val
s, you can get rid of interfaces and use just implementation classes.
回答2:
Answered by Dmitry Jemerov on the kotlinlang Slack group:
The only possibility is to use reflection. Pass a dummy B instance to the constructor of A, then create a real instance of B passing the A instance as a parameter, and then use reflection to change the value of “f” field in the A instance to the B instance.
But I would strongly suggest you to not do that, and instead to reconsider your data model.
回答3:
Passing an object which is not constructed yet as argument seems to be impossible. So, I think such cross-reference initialization is not possible with original data classes.
But some workaround could be done though:
data class A(val f: A.() -> B)
data class B(val f: B.() -> A)
val A.b: B get() = f(this)
val B.a: A get() = f(this)
fun test() {
val O = object {
val refA: A = A { refB }
val refB: B = B { refA }
}
var a = O.refA
var b = O.refB
// validating cross-refs
require( a === b.a )
require( b === a.b )
require( b === b.a.b )
require( a === a.b.a )
println("Done.")
}
来源:https://stackoverflow.com/questions/35439421/circular-references-with-vals-in-kotlin