出于测试目的,我想计算懒惰的2个元素:
Stream(
{ Thread.sleep(2000); 1 },
{ Thread.sleep(2000); 2 },
Stream.empty[Int]
).foreach(println)
但是运行此代码不会产生预期的结果。值似乎在输出中同时显示所有值。原因是Stream()
构造函数正在采用必须急切计算的数组。所以要解决这个问题,我不得不采用手动创建流的thunk:
(
{ Thread.sleep(2000); 1 } #::
{ Thread.sleep(2000); 2 } #::
Stream.empty[Int]
).foreach(println)
现在完全按照预期工作,但不是特别漂亮。
是否有一种更清晰,更方便的方法,可以在语法上与Stream(a, b, c)
类似,但是懒惰地评估这些参数?
由于
答案 0 :(得分:2)
如果你创建一个特殊的类,它可以保存生成A
的名字块,以及一个帮助实例化这个类的简短助手方法:
class ByNameArg[+A](a: => A) {
def unpack: A = a
}
/** Single lazy by-name argument wrapper */
def l[A](a: => A) = new ByNameArg(a)
然后您可以定义以下工厂方法:
def lazyStreamInit[A](xs: ByNameArg[A]*): Stream[A] = {
if (xs.isEmpty) {
Stream.empty[A]
} else {
xs.head.unpack #:: lazyStreamInit(xs.tail: _*)
}
}
它可以用很少的语法开销(你只需要在vararg-list中传递的每个块前加一个字符l
):
lazyStreamInit(
l{ Thread.sleep(2000); 1 },
l{ Thread.sleep(2000); 2 }
)
与通常的() => A
- 解决方法相比,这会直接产生Stream[A]
,而不是Stream[() => A]
。
摆脱l
或{ () => ... }
似乎不可能,因为repeated by-name arguments are not supported。
修改强>
通过“通常() => A
- 解决方法”我的意思是
Stream(
{ () => Thread.sleep(2000); 1 },
{ () => Thread.sleep(2000); 2 }
).map{ _() }.foreach(println)
请注意,您必须附加一个map
步骤才能使其成为Stream[A]
。
答案 1 :(得分:1)
这将需要重复的名称参数,这些参数目前不受支持(http://docs.scala-lang.org/sips/repeated-byname.html,https://github.com/scala/bug/issues/5787)。不过,它们可用in Dotty。
你可以使用重复的() => A
,但是你需要写
def makeStream[A](xs: (() => A)*) = ...
makeStream(
{ () => Thread.sleep(2000); 1 },
{ () => Thread.sleep(2000); 2 }
).foreach(println)