Scala中val与def定义函数的编译机制差异问询
Scala中def方法与函数字面量的编译差异
好问题!这其实是Scala里**方法(method)和函数值(function value)**的核心区别之一,我来给你掰扯清楚:
1. 函数字面量(val定义)的编译逻辑
你提到的val fIncr: (x: Int) => x+1这种函数字面量,编译器确实会把它编译成一个继承Function1[Int, Int]特质的匿名类,运行时实例化后将这个对象赋值给fIncr。就像你给出的交互示例:
scala> val double = (i: Int) => { | println("I am here") | i * 2 | } double: Int => Int = $$Lambda$1090/...
这里的$$Lambda$xxx就是JVM层面生成的匿名Function子类实例,它是个实打实的对象,可以被当作参数传递、存入集合,或者像普通对象一样操作。
2. def定义的方法的编译逻辑
而def mIncr(x: Int) = x+1定义的是一个普通方法,它本质是所属类(或单例对象)的成员,编译后会直接成为JVM的普通方法(类似Java里的方法),不会自动编译成Function1的类实例。
不过有个特殊情况:当你在需要函数类型的上下文里使用这个方法时,编译器会自动帮你做一个叫做eta-expansion的转换,把方法转换成对应的Function1实例。比如:
scala> def mIncr(x: Int) = x + 1 mIncr: (x: Int)Int scala> // 手动触发eta-expansion:使用下划线 scala> val f = mIncr _ f: Int => Int = $$Lambda$1105/... scala> // 自动触发:在需要函数类型的场景下 scala> val list = List(1,2,3) scala> list.map(mIncr) // 这里编译器自动把mIncr转成函数值 res0: List[Int] = List(2, 3, 4)
只有在这种转换发生的时候,编译器才会生成对应的Function子类实例,否则mIncr就是一个普通的方法,不是对象。
简单总结
- 函数字面量(val + =>):天生就是函数值对象,编译时直接生成Function子类
- def方法:默认是普通JVM方法,只有在需要函数值的场景下才会被转换为Function实例
内容的提问来源于stack exchange,提问作者Mandroid
相关产品推荐
相关产品推荐

