Scala按名称调用参数:是否等价于无参函数?其实现原理是什么?
Scala中按名称调用参数(
=> A)与无参函数(() => A)的区别及底层实现 问题场景
我在阅读Scala红宝书时,书中提到=> A是() => A的简洁语法,但实际测试发现以下两个函数定义并不等价:
def nonStrict[A](a: () => A) = adef nonStrict[A](a: => A) = a
测试代码及结果
scala> def nonStrict[A](a: => A) = a def nonStrict[A](a: => A): A scala> nonStrict[Int](1) val res13: Int = 1 scala> def nonStrict[A](a: () => A) = a def nonStrict[A](a: () => A): () => A scala> nonStrict[Int](() => 1) val res14: () => Int = $Lambda$1325/0x000000080110ea58@35af404f scala> nonStrict[Int](1) ^ error: type mismatch; found : Int(1) required: () => Int
核心疑问解答
- 传入
aa: A时是否自动包装为() => aa?
是的,但这种包装是编译器自动完成的特殊延迟求值包装,和显式写() => aa的无参函数有本质区别:
- 调用按名称参数版本的
nonStrict[Int](1)时,编译器会把1这个表达式包装成一个“可延迟执行的代码块”,每次在函数体内引用a时,都会执行这个代码块并返回结果。 - 显式的
() => A是普通的无参函数实例,你可以把它赋值给变量、传递给其他函数,它本身不会自动执行,必须显式调用()才会求值。
- 为什么两个函数的返回值类型不同?
- 对于
def nonStrict[A](a: => A) = a:函数体内的a是对延迟代码块的求值,所以返回类型是A。 - 对于
def nonStrict[A](a: () => A) = a:函数直接返回传入的无参函数实例,所以返回类型是() => A。
底层实现原理
Scala的按名称调用参数(=> A)底层是通过编译器生成一个特殊的Function0[A]子类实例实现的,但这个实例是编译器隐式生成的,和手动写的() => A lambda有以下差异:
- 按名称参数的包装代码块每次引用都会重新执行,而普通无参函数若无副作用,多次调用结果一致,但调用时机由你控制。
- 编译器对按名称参数做了语法糖处理:不需要显式写
()调用,直接引用参数名就会触发求值;普通无参函数必须显式调用()才会执行。 - 按名称参数不能直接当作普通函数传递(比如不能把
a: => A赋值给() => A类型变量,除非手动转换:val f: () => A = () => a)。
简单来说,=> A不是() => A的缩写,而是Scala提供的延迟求值语法糖,它的语义是“一段可延迟执行的代码,返回类型为A”;而() => A是普通的无参函数类型,代表一个可被调用的函数实例。
内容的提问来源于stack exchange,提问作者al249
相关产品推荐
相关产品推荐

