Scala解释器为何会对Stream求值?新手技术问询
为什么你的第二个Scala Stream被提前求值了?
嘿,作为Scala新手碰到这个问题太正常了!先猜猜你可能写的代码大概是这样的:
// 第一个Stream,正常惰性显示 val s1 = Stream.cons('?', s1) // 第二个Stream,被意外求值了 val s2 = Stream('?', s2)
如果是这样的话,问题核心出在Stream的构造方式差异上:
1. 为什么第一个Stream能保持惰性?
Stream.cons方法的第二个参数是按名参数(by-name parameter)——它不会在构造Stream的瞬间就求值,而是会等到你真正需要访问这个位置的元素时,才会触发计算逻辑。所以Stream.cons('?', s1)创建的是一个无限循环的惰性Stream,Scala解释器只会展示头部的?,不会傻乎乎地递归求值整个无限序列。
2. 为什么第二个Stream被强制求值了?
Stream(...)是调用了Stream.apply方法,这个方法的参数是可变参数(A*),它的逻辑是先把所有传入的参数立即求值,再把它们包装成Stream。当你把s2作为第二个参数传进去时,Scala会先尝试计算s2的值,但s2此时还在定义过程中,这就触发了无限递归的求值链——解释器不得不拼命解析s2,自然就打破了惰性的预期。
正确的惰性无限Stream构造方式
如果你想创建类似的惰性无限Stream,推荐这两种写法:
- 用Stream的
::操作符(内部本质还是调用cons):
val s2 = '?' :: s2
- 用更直观的
Stream.continually:
val s3 = Stream.continually('?')
这两种方式创建的Stream都会严格保持惰性,只有当你调用head、take这类触发元素访问的方法时,才会真正求值。
内容的提问来源于stack exchange,提问作者unj2
相关产品推荐
相关产品推荐

