试图从Scala编程,第2版中找出本节的重要性。
函数文字被编译成一个实例化的类 运行时是一个函数值。从而区分功能 文字和值是函数文字存在于源中 代码,而函数值在运行时作为对象存在。该 区别很像类(源代码)和 对象(运行时)。
我真的没有得到他们在这里想说的话。该函数值不存在于源代码中,函数文字在运行时不存在?
// literal
val addOne = (x: Int) => x + 1
// value
def add1(x: Int): Int = x + 1
我可以传递给另一个函数:
def doThing(thing: Int => Int) = thing(5)
doThing(addOne) // 6
doThing(add1) // 6
似乎函数文字被放置在一个继承自FunctionN
的类中(其中N是函数的arity)。他们试图在这里做出什么区别?
答案 0 :(得分:4)
我真的没有得到他们在这里想说的话。
函数文字和值的示例不准确。本书不是将方法与函数进行比较,而是在函数的两个不同“模式”之间进行区分。提示在第一句话中:
函数文字被编译成一个实例化的类 运行时是一个函数值。
在编译时输入:
val addOne = (x: Int) => x + 1
这是本书所称的“函数文字”(或Anonymous Function)。通过键入:
,与获得字符串文字的方式相同val s = "Hello, World"
编译器的 addOne
为Function1[Int, Int]
,意味着需要Int
并返回Int
结果。函数文字语法((x: Int) => x + 1
)是FunctionN
的语法糖,其中N
由函数的arity确定。
在运行时,编译器通过实例化Function1[Int, Int]
类型的对象来获取此“函数文字”并“将生命放入其中”,从而创建一个函数值,您可以调用,传递等等。
他们想在这里做出什么区别?
本书基本上试图在函数的编译时和运行时表示之间进行区分,所以当他们说“函数文字”时,你会理解他们在谈论前者,当他们说“函数值”时“后者。
答案 1 :(得分:3)
Scala代码编译成jvm字节码,它没有函数但有类。所以你的代码val addOne = (x: Int) => x + 1
是语法糖(我这里不精确,只有高概念):
final class anonFun extends scala.runtime.AbstractFunction1 {
final def apply(x: Int) = x + 1
}
val addOne = new anonFun();
实际编译的文件要复杂得多,您可以使用scalac -print
编译scala文件并查看desugared scala代码。这是我的小对象的编译输出:
object Main {
val addOne = (x: Int) => x + 1
}
(scalac 2.11.7版)
package <empty> {
object Main extends Object {
private[this] val addOne: Function1 = _;
<stable> <accessor> def addOne(): Function1 = Main.this.addOne;
def <init>(): Main.type = {
Main.super.<init>();
Main.this.addOne = {
(new <$anon: Function1>(): Function1)
};
()
}
};
@SerialVersionUID(value = 0) final <synthetic> class anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp with Serializable {
final def apply(x: Int): Int = anonfun$1.this.apply$mcII$sp(x);
<specialized> def apply$mcII$sp(x: Int): Int = x.+(1);
final <bridge> <artifact> def apply(v1: Object): Object = scala.Int.box(anonfun$1.this.apply(scala.Int.unbox(v1)));
def <init>(): <$anon: Function1> = {
anonfun$1.super.<init>();
()
}
}
}
对比看看编译
object Main {
def addOne(i: Int) = i + 1
}
(scalac 2.11.7版)
package <empty> {
object Main extends Object {
def addOne(i: Int): Int = i.+(1);
def <init>(): Main.type = {
Main.super.<init>();
()
}
}
}
您可以看到def addOne
只是对象的实例方法,但val addOne
本身就是一个对象。
答案 2 :(得分:0)
该段落中的功能没什么特别之处。它适用于其他类型的文字,例如整数。
0x34
的字符组成的特定字符序列,后跟具有ASCII值0x32
的字符,并由空格,括号,逗号,分号或其他类型的分隔符包围,是一个整数文字。Int
类的实例。 (实际上,这并不完全正确:在Scala的JVM实现上,它将被编译成JVM原语int
,并且在Scala的ECMAScript实现上,它将被编译成ECMAScript Number
,并且编译器将生成额外的代码以“伪造”它作为scala.Int
类的实例。)42
的整数。这里的功能没有什么不同。构成文字的特定字符序列(无论是函数文字,整数文字,字符串文字,字符文字,符号文字,元组文字,布尔字面值还是文字值null
)仅存在于源代码。这些文字表示的值仅在运行时存在。这些文字的编译时表示形式是某个类的实例。