函数文字与函数值

时间:2016-05-07 08:18:51

标签: scala function

试图从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)。他们试图在这里做出什么区别?

3 个答案:

答案 0 :(得分:4)

  

我真的没有得到他们在这里想说的话。

函数文字和值的示例不准确。本书不是将方法函数进行比较,而是在函数的两个不同“模式”之间进行区分。提示在第一句话中:

  

函数文字被编译成一个实例化的类   运行时是一个函数值。

在编译时输入:

val addOne = (x: Int) => x + 1

这是本书所称的“函数文字”(或Anonymous Function)。通过键入:

,与获得字符串文字的方式相同
val s = "Hello, World"
编译器的

addOneFunction1[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)

该段落中的功能没什么特别之处。它适用于其他类型的文字,例如整数。

  • 由具有ASCII值0x34的字符组成的特定字符序列,后跟具有ASCII值0x32的字符,并由空格,括号,逗号,分号或其他类型的分隔符包围,是一个整数文字。
  • 它将被编译为Int类的实例。 (实际上,这并不完全正确:在Scala的JVM实现上,它将被编译成JVM原语int,并且在Scala的ECMAScript实现上,它将被编译成ECMAScript Number,并且编译器将生成额外的代码以“伪造”它作为scala.Int类的实例。)
  • 在运行时,它将被实例化为表示值42的整数。

这里的功能没有什么不同。构成文字的特定字符序列(无论是函数文字,整数文字,字符串文字,字符文字,符号文字,元组文字,布尔字面值还是文字值null)仅存在于源代码。这些文字表示的值仅在运行时存在。这些文字的编译时表示形式是某个类的实例。