【问题标题】:Scala Lazy Val QuestionScala Lazy Val 问题
【发布时间】:2011-06-11 12:14:52
【问题描述】:

我有一个场景,我有一些需要相互引用的对象。我可以编译它的唯一方法是使用 lazy

class A(b:B)
class B(a:A)
lazy val a:A = new A(b)
lazy val b:B = new B(a)

我可以使用一些演员做同样的事情,并让它编译

    abstract class Message
    case class Message1 extends Message
    case class Message2 extends Message

    class Actor1(otherActor:Actor) extends Actor {
        def act() {
            loop {
                react {
                    case Message1 =>
                        println("received message1")
                        otherActor ! Message2
                    case _ =>
                }
            }
        }
    }

    class Actor2(otherActor:Actor) extends Actor {
        def act() {
            loop {
                react {
                    case Message2 =>
                        println("received message2")
                        otherActor ! Message1
                    case _ =>
                }
            }
        }
    }

    lazy val actor1:Actor = new Actor1(actor2)
    lazy val actor2:Actor = new Actor2(actor1)

但是,当我添加以下内容时:

    actor1.start
    actor2.start
    actor1 ! Message1

我收到以下错误:

线程“main”中的异常 java.lang.NoClassDefFoundError: com/fictitiousCompany/stackOverflowQuestion/Test 造成的: java.lang.ClassNotFoundException: com.fictitiousCompany.stackOverflowQuestion.Test 在 java.net.URLClassLoader$1.run(URLClassLoader.java:202) 在 java.security.AccessController.doPrivileged(本机 方法)在 java.net.URLClassLoader.findClass(URLClassLoader.java:190) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:307) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:248)

我正在使用 Scala Eclipse 插件 2.8.1。

【问题讨论】:

  • 我怀疑存在一个单独的问题,即 Eclipse 没有正确设置类路径。您可能想尝试命令行 scala -cp classes com.fictitious.stackOverflowQuestion.Test,其中 classes 指向生成的类文件。
  • 奇怪的是,在此之前我可以使用 Eclipse 编写一些相对复杂的代码而不会出现任何问题。我的其他代码仍在运行。也许这是一个 Eclipse 插件错误...?
  • 今天晚些时候我将不得不为整个相互依赖对象列表处理这个问题。
  • @Raphael。凉爽的。我实际上有一个相互依赖对象的列表,但将其归结为这个最简单的情况。期待看到你的想法。
  • 解决了;实际上是对 huynhjl 答案的或多或少的简单概括。不过这里不适合。

标签: scala reference actor lazy-evaluation forward


【解决方案1】:

请注意,即使是较小的示例也会有问题(在 REPL 中):

{
class A(b:B)
class B(a:A)
lazy val a:A = new A(b)
lazy val b:B = new B(a)
a
}
// causes stack overflow error

一旦需要评估 a 并因此构造它,它就需要 B,而 B 需要 A。为了使其工作 ab 必须完成构造。

使用按名称参数可以评估较小的示例。

{
class A(b: => B)
class B(a: => A)
lazy val a:A = new A(b)
lazy val b:B = new B(a)
a
}

请注意确定这是否也适用于您的演员示例。

编辑:按名称参数在 2.8.0 本地工作。我用对象替换了案例类以消除一些弃用警告,并在 actor1、actor2 上添加了启动方法,并用actor1 ! Message1 踢了整个事情。除此之外,我之前没有使用过actor,所以我无法发表更多评论。这是我测试的:

import scala.actors._

abstract class Message
object Message1 extends Message
object Message2 extends Message

class Actor1(otherActor: => Actor) extends Actor {
def act() {
    loop {
    react {
        case Message1 =>
        println("received message1")
        otherActor ! Message2
        case _ =>
    }
    }
}
}

class Actor2(otherActor: => Actor) extends Actor {
def act() {
    loop {
    react {
        case Message2 =>
        println("received message2")
        otherActor ! Message1
        case _ =>
    }
    }
}
}

{
  lazy val actor1:Actor = new Actor1(actor2)
  lazy val actor2:Actor = new Actor2(actor1)
  actor1.start
  actor2.start
  actor1 ! Message1
}

打印一堆:

received message1
received message2

【讨论】:

  • 感谢您的提示。演员示例仍然存在相同的问题
  • 如果通过编辑您指的是“按名称”参数构造otherActor: => Actor,这是因为在调用方法时不会评估参数。相反,编译器会保存表达式,并且每次在 Actor1 或 Actor2 中使用 otherActor 时,都会计算表达式。因此,当您调用 new Actor1(actor2) 时,actor2 表达式不会在该点进行评估,从而允许构造对象。按名称参数通常用于创建自定义控件抽象,如循环。
  • 很可能不是很好。可能至少存在一种间接方式。此外,如果您使用 new Actor1(new Actor2) 之类的东西,您必须小心,因为每次都会创建一个新对象,这不是您所追求的。我认为一定有比在构造函数中传递引用的actor更好的设计模式。
  • @huynhjl。我用这种方法意识到的一件事是对象 Message1 不能接受参数,这是我试图解决的现实世界问题的一个问题。有什么想法吗?
  • @huynhjl。是的,你是对的,有一个更好的设计涉及演员工厂
猜你喜欢
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 2015-07-20
  • 2013-05-15
  • 1970-01-01
  • 2011-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多