如何很好地初始化这样的结构:
case class A(name: String, b: B)
case class B(name: String, a: A)
寻找没有延迟val的解决方案(性能开销)并且不向现有案例类添加新成员(它看起来很丑陋),但特殊封装器和原始类型签名的更改可能没什么问题(至少我是最好的)得到了)。 toString-problem可以忽略不计,因为我可以在某些特征中覆盖它。
答案 0 :(得分:0)
现在,我想出了这个:
case class Chicken[T](h: Holder[T, _]) {
def get = h.chicken
override def toString = get.toString
}
case class Egg[U](h: Holder[_, U]) {
def get = h.egg
override def toString = get.toString
}
implicit def egg[T] = (_: Egg[T]).get
implicit def chicken[T] = (_: Chicken[T]).get
case class Holder[U, T] (chickenF: (Egg[T], Chicken[U]) => (U, T)) {
val (chicken, egg) = chickenF( Egg(this), Chicken(this))
}
def mutual[U, T](chickenF: (Egg[T], Chicken[U]) => (U, T)) = {
val h = new Holder(chickenF)
h.chicken -> h.egg
}
trait Named { //to avoid unfinite toString
def name: String
override def toString = name
}
用法:
case class A(name: String, b: Egg[B])
case class B(name: String, a: Chicken[A]) extends Named
val (a, b) = mutual[A, B](A("a", _) -> B("b", _))
val (a2, b2) = mutual[A, B]{ (b2, a2) => //alternative for complex cases
A("a", b2) -> B("b", a2)
}
println(a)
println(b)
println(a.b)
println(b.a)
结果:
A(a,b)
b
b
A(a,b)
仍然希望有一个库,比如scalaz或基于宏的解决方案。
答案 1 :(得分:0)
我找到一段时间来处理这个问题的另一种方法(虽然我现在更喜欢设计我的类型,这些循环引用没有出现),是传递一个生成器函数来获取这些值,而不是值直接(或替换为您的Chicken
和Egg
类型)。例如:
trait Named { //to avoid infinite toString, as before
def name: String
override def toString = name
}
case class A(name: String, generator: A => B) extends Named { val b: B = generator(this) }
case class B(name: String, a: A) extends Named // Either or both types could extend Named
使用示例:
scala> def generator(name: String)(a: A): B = B(name, a)
generator: (name: String)(a: A)B
scala> val a = A("a", generator("b"))
a: A = a
scala> a.b
res6: B = b