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

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 に答える
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: Aされていないという利点がありa: Lazy[A]ます。

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

でラップされた実際の値にアクセスするには、または(またはのように)をLazy使用できることに注意してください。applyvaluex.a()x.a.value

于 2014-02-05T14:10:29.717 に答える
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 に答える