Scala中惰性创建多元素Stream失效,求正确实现方式
正确创建多元素惰性Stream(或LazyList)的方式
嗨,这个坑我之前也踩过!你遇到的问题核心在于Scala的Stream(...)构造器并不是惰性的——它接收的可变参数会在调用方法时立即全部求值,所以你的两个sleep代码块在Stream(...)被调用的瞬间就执行了,自然会同时输出结果。
下面给你几种正确的惰性创建方式,按推荐程度排序:
1. 使用#::操作符(最简洁的语法糖)
#::是Stream.cons的语法糖,它的第一个参数是传名参数(只有在被访问时才会求值),而且是右结合的,非常适合构建惰性序列:
val lazyStream = ({ Thread.sleep(2000); 1 }) #:: ({ Thread.sleep(2000); 2 }) #:: Stream.empty[Int] lazyStream.foreach(println)
运行这段代码,你会看到先等待2秒输出1,再等待2秒输出2,完全符合惰性计算的预期。
2. 直接使用Stream.cons
如果想更明确地表达构造逻辑,可以直接调用Stream.cons方法,它的第一个参数是传名的,第二个参数是后续的Stream:
val lazyStream = Stream.cons( { Thread.sleep(2000); 1 }, Stream.cons( { Thread.sleep(2000); 2 }, Stream.empty[Int] ) ) lazyStream.foreach(println)
这个和用#::的效果完全一致,只是写法更冗长一些。
3. 迁移到LazyList(Scala 2.13+推荐)
在Scala 2.13及以后的版本中,Stream已经被标记为过时(deprecated),官方推荐使用LazyList——它是Stream的改进版,解决了一些历史遗留的线程安全和内存泄漏问题。用法和Stream几乎完全一样:
val lazyList = ({ Thread.sleep(2000); 1 }) #:: ({ Thread.sleep(2000); 2 }) #:: LazyList.empty[Int] lazyList.foreach(println)
补充说明:为什么Stream(...)不行?
你可以看一下Stream.apply的简化源码:
def apply[A](xs: A*): Stream[A] = xs.toStream
它接收的是一个可变参数数组xs: A*,而Java/Scala中可变参数在调用时会先把所有参数求值,再打包成数组传入,所以你的两个代码块在调用Stream(...)时就已经执行了,根本没机会惰性求值。
内容的提问来源于stack exchange,提问作者devoured elysium
相关产品推荐
相关产品推荐

