6

这是我的尝试:

case class A(val a: A, val b: Int){
    override def toString() = b.toString
}

lazy val x: A = A(y, 0)
lazy val y: A = A(z, 1)
lazy val z: A = A(x, 2)

当试图用 x 做任何事情时,问题就来了;导致 x 被评估以循环评估开始,通过 x、y、z 并以堆栈溢出结束。有没有办法指定 val a 应该延迟计算?

4

4 回答 4

8

你可以这样使用Stream

lazy val stream: Stream[Int] = 0 #:: 1 #:: 2 #:: stream

stream.take(10).toList
// List(0, 1, 2, 0, 1, 2, 0, 1, 2, 0)

一般来说,您应该使用call-by-name参数:

class A(_a: => A, val b: Int) {
    lazy val a = _a
    override def toString() = s"A($b)"
}

用法:

scala> :paste
// Entering paste mode (ctrl-D to finish)

lazy val x: A = new A(y, 0)
lazy val y: A = new A(z, 1)
lazy val z: A = new A(x, 2)

// Exiting paste mode, now interpreting.

x: A = <lazy>
y: A = <lazy>
z: A = <lazy>

scala> z.a.a.a.a.a
res0: A = A(1)
于 2014-02-05T13:58:41.593 回答
3

你需要让A.a 自己变得懒惰。您可以通过将其转换为用于初始化惰性字段的按名称参数来实现:

class A(a0: => A, val b: Int){
  lazy val a = a0
  override def toString() = b.toString
}
object A {
  def apply( a0: => A, b: Int ) = new A( a0, b )
}

你也可以使用辅助类来做同样的事情Lazy

implicit class Lazy[T]( getValue: => T ) extends Proxy {
  def apply(): T = value
  lazy val value = getValue
  def self = value
}

它的优点是您的代码几乎没有变化,除了更改a: Aa: Lazy[A]

case class A(val a: Lazy[A], val b: Int){
 override def toString() = b.toString
}

请注意,要访问包含在 中的实际值Lazy,您可以使用applyor value(如在x.a()or中x.a.value

于 2014-02-05T14:10:29.717 回答
3

Stream您可以使用数据类型定义一个惰性循环列表:

lazy val circular: Stream[Int] = 1 #:: 2 #:: 3 #:: circular

您可以使用名称参数自己执行相同的技巧:

class A(head: Int, tail: => A)
lazy val x = new A(0, y)
lazy val y = new A(1, z)
lazy val z = new A(2, x)

请注意,这不适用于案例类。

于 2014-02-05T13:59:18.910 回答
2

您可以使用按名称参数。

class A(__a: => A, val b: Int) {
  def a = __a
  override def toString() = b.toString
}
object A {
  def apply(a: => A, b: Int) = new A(a, b)
}
于 2014-02-05T14:01:30.010 回答