我一直想着如何使用不可变的case类在Scala中实现双链接树或列表.对于大多数"更新"操作,我一直在使用复制和更新方法.例如,在设置父母的孩子时,我说
parent = parent.copy(child=child)
Run Code Online (Sandbox Code Playgroud)
或者在设置孩子的父母时,我说
child = child.copy(parent=parent)
Run Code Online (Sandbox Code Playgroud)
我意识到,如果我将父级设置为包含子级,然后创建并更新新子级以包含父级,则父级将包含对旧子级的引用.同样,如果我试图反过来做,那么孩子将包含对旧父母的引用.
我希望我的树能够双重联系,所以我可以双向爬行:从根到他的孩子,或者从叶子向上到父母.是否有可能以这种方式"同时"链接父节点和子节点,给我循环引用,然后我可以双向爬行?
我可以使用可变数据轻松地做到这一点,但在我的情况下,双重链接树将在创建后存在很长时间,并且如果可能的话我想保持它不变.
假设我有一个像这样的愚蠢的小案例类:
case class Foo(name: String, other: Foo)
Run Code Online (Sandbox Code Playgroud)
我如何定义a和b不可改变这样a.other的b,而且b.other是a?scala是否提供了"打结"的方法?我想做这样的事情:
val (a, b): (Foo, Foo) = (Foo("a", b), Foo("b", a)) // Doesn't work.
Run Code Online (Sandbox Code Playgroud)
可能性
在Haskell中,我会这样做:
data Foo = Foo { name :: String, other :: Foo }
a = Foo "a" b
b = Foo "b" a
Run Code Online (Sandbox Code Playgroud)
绑定到a和b包含在同一let表达式中或顶层的绑定.
或者,在不滥用Haskell的自动化letrec功能的情况下:
(a, b) = fix (\ ~(a', b') -> Foo "a" b', Foo "b" …Run Code Online (Sandbox Code Playgroud) 我不小心遇到了这种情况(简化示例以解决问题):
abstract class Element(val other: Element)
case object First extends Element(Second)
case object Second extends Element(First)
object Main {
def main(arguments: Array[String]) {
val e1 = First
val e2 = Second
println("e1: "+e1+" e1.other: "+e1.other)
println("e2: "+e2+" e2.other: "+e2.other)
}
}
Run Code Online (Sandbox Code Playgroud)
有人想猜测输出吗?:-)
e1: First e1.other: Second
e2: Second e2.other: null
Run Code Online (Sandbox Code Playgroud)
输出有点意义.显然,在创建第二个对象时,第一个对象尚不存在,因此null被分配.问题是......这是错的!我花了几个小时跟踪这个.编译器不应该说出这个吗?有趣的是,当我尝试将事物作为Scala脚本运行时(相同的代码,减号object Main和def main行,以及关闭}s),我得到了一个无限的序列(不是真的无限 - 在某些时候列表停止,我想由于一些限制关于Exception痕迹的深度,或类似的异常,如下所示:
vilius@blackone:~$ scala 1.scala
...
at Main$$anon$1.Main$$anon$$Second(1.scala:4)
at Main$$anon$1$First$.<init>(1.scala:3)
at Main$$anon$1.Main$$anon$$First(1.scala:3)
at Main$$anon$1$Second$.<init>(1.scala:4)
at Main$$anon$1.Main$$anon$$Second(1.scala:4)
at Main$$anon$1$First$.<init>(1.scala:3)
... …Run Code Online (Sandbox Code Playgroud) 我有一个Brand类,有几个产品
在产品类中,我希望对品牌有一个参考,如下所示:
case class Brand(val name:String, val products: List[Product])
case class Product(val name: String, val brand: Brand)
Run Code Online (Sandbox Code Playgroud)
我怎么能把这些课程打包?
我的意思是,除非我有品牌,否则我无法创造产品
除非我有产品清单(因为Brand.products是val),否则我无法创建品牌
建模这种关系的最佳方法是什么?
我正在尝试写一个叫做ActorManager另一个演员叫的演员RealActor.我们的想法是ActorManager可以处理所有进出的消息RealActor,允许添加其他逻辑,如过滤或缓冲.外部世界应该RealActor通过其经理与唯一的交流,就像在现实世界中一样.
初稿看起来像这样:
class ActorManager(realActor: ActorRef) extends Actor {
def receive = {
case _ => { /* pre-process messages */ }
}
}
class RealActor(actorManager: ActorRef) extends Actor {
def receive = {
case _ => { /* actual business logic */ }
}
}
Run Code Online (Sandbox Code Playgroud)
然而,这提出了如何一次构建两个actor,或者更具体地说如何定义Props两个actor的循环依赖关系的问题.我不确定定义时一般lazy val模式是否适用Props.
我还想避免首先构建两个中的一个,并引入一个显式Register协议来连接它们.