这是我的尝试:
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 应该延迟计算?
这是我的尝试:
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 应该延迟计算?
你可以这样使用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)
你需要让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: A
为a: Lazy[A]
:
case class A(val a: Lazy[A], val b: Int){
override def toString() = b.toString
}
请注意,要访问包含在 中的实际值Lazy
,您可以使用apply
or value
(如在x.a()
or中x.a.value
)
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)
请注意,这不适用于案例类。
您可以使用按名称参数。
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)
}