以下在Scala中编写函数的方法有什么不同?

以下在Scala中编写函数的方法有什么不同?,scala,Scala,我是Scala的新手,见过很多定义函数的方法,但找不到关于差异的明确解释,以及何时使用哪种形式 以下函数定义之间的主要区别是什么 用“=”表示 def func1(node: scala.xml.Node) = { print(node.label + " = " + node.text + ",") } 没有“=” def func2 (node: scala.xml.Node) { print(node.label + " = " + node.text + ",") }

我是Scala的新手,见过很多定义函数的方法,但找不到关于差异的明确解释,以及何时使用哪种形式

以下函数定义之间的主要区别是什么

  • 用“=”表示

    def func1(node: scala.xml.Node) = {
        print(node.label + " = " + node.text + ",")
    }
    
  • 没有“=”

    def func2 (node: scala.xml.Node) {
        print(node.label + " = " + node.text + ",")
    }
    
  • 带“=>”的

    def func3 = (node: scala.xml.Node) => {
        print(node.label + " = " + node.text + ",")
    }
    
  • 作为var

    var func4 = (node: scala.xml.Node) => {
        print(node.label + " = " + node.text + ",")
    }
    
  • 无障碍

    def func5 (node: scala.xml.Node) = print(node.label + " = " + node.text + ",")  
    
  • 它们在用作对象的回调时似乎都编译并呈现相同的结果

        xmlNodes.iterator.foreach(...)
    
    • 每次生成的字节码有什么不同吗
    • 什么时候使用哪种形式有什么指南吗

    • 是的,字节码之间存在差异。是的,有一些指导方针

    • With
      =
      :这声明了一个方法,该方法接受参数并返回右侧块中的最后一个表达式,其类型为
      Unit

    • =
      :这声明了一个没有返回值的方法,即返回类型始终为
      单位
      ,而不管右侧块中最后一个表达式的类型是什么

    • With
      =>
      :这声明了一个方法,返回类型为
      scala.xml.Node=>Unit
      的函数对象。每次调用此方法
      func3
      ,都会在堆上构造一个新的函数对象。如果您编写
      func3(节点)
      ,您将首先调用返回函数对象的
      func3
      ,然后在该函数对象上调用
      apply(节点)
      。这比在案例1中直接调用普通方法要慢。二,

    • 作为
      var
      :这声明了一个变量并创建了一个函数对象,如3所示,但函数对象只创建一次。在大多数情况下,使用它来调用函数对象比简单的方法调用慢(JIT可能不会内联),但至少不会重新创建对象。如果要避免有人重新分配变量
      func4
      ,请改用
      val
      lazy val

    • 这是1的语法糖。当块仅包含一个表达式时

    • 请注意,如果使用表格1,2。五,。使用更高阶的
      foreach
      方法,Scala仍然会创建一个函数对象,隐式调用
      func1
      func2
      func5
      ,并将其传递给
      foreach
      (它不会使用方法句柄或类似的smth,至少在当前版本中不会这样)。 在这些情况下,生成的代码大致对应于:

      xmlNodes.iterator.foreach((node: scala.xml.Node) => funcX(node))
      
      因此,指导原则是-除非每次都使用相同的函数对象,否则只需创建一个普通方法,如1,2所示。或5。无论如何,它都会被提升到一个函数对象,在需要的地方。 如果您意识到调用这种方法经常会产生很多对象,那么您可能需要使用表单4进行微优化。而是确保只创建一次
      foreach
      的函数对象

      在1,2之间决定。五,。关于这一点,有一条准则是——如果你只有一条陈述,请使用表格5

      否则,如果返回类型是
      Unit
      ,则如果这是公共API,则使用
      def foo():Unit={
      表单,以便查看代码的客户端快速、清晰地看到返回类型。 对于返回类型为私有的
      Unit
      方法,请使用
      def foo(){
      表单,以方便您编写较短的代码。但这只是有关样式的一个特定准则


      有关更多信息,请参阅:

      1-2。当您扔掉等号时,您的函数将变成过程(返回单位,或什么都不返回)。
      3.在第三种情况下,您定义了一个返回函数的函数
      scala.xml.Node=>Unit

      4.相同,但您已经为变量分配了一些函数
      scala.xml.Node=>Unit
      。差异在

      5.与1相比没有区别。但是你不能写那样的多行语句。

      好吧,1、2和5根本不是函数,它们是方法,与函数有根本的不同:方法属于对象,本身不是对象,而函数是对象

      1、2和5也完全相同:如果只有一条语句,那么不需要大括号来组合多条语句,因此5和1是一样的。去掉
      =
      符号是声明
      Unit
      返回类型的语法糖衣,但是
      Unit
      也是1和5的推断返回类型,因此2是same为1和5


      3是一个调用时返回函数的方法。4是一个指向函数的变量。

      这些问题中的每一个都在本网站的其他地方得到了回答,但我认为没有任何东西能够同时处理它们。因此:

      大括号与等号 用等号定义的方法返回一个值(不管最后一个值是什么).仅使用大括号定义的方法返回
      单位
      。如果使用等于但最后一个值求值为
      单位
      ,则没有区别。如果是等号后的单个语句,则不需要大括号;这与字节码没有区别。因此,1、2和5基本上都是相同的:

      def f1(s: String) = { println(s) }     // println returns `Unit`
      def f2(s: String) { println(s) }       // `Unit` return again
      def f5(s: String) = println(s)         // Don't need braces; there's only one statement
      
      函数与方法 通常编写为
      A=>B
      的函数是
      函数
      类之一的子类,例如
      Function1[A,B]
      。因为这个类有一个
      apply
      方法,当您只使用没有方法名的parens时,Scala会神奇地调用该方法,所以它看起来像是一个方法调用——事实上是这样的,除了它是对
      函数
      对象的调用

      def f3 = (s: String) => println(s)
      
      然后您要说的是“
      f3
      应该创建一个
      Function1[String,Unit]
      的实例,它有一个
      apply
      方法,看起来像
      def apply(s:String)=println(s)
      val f4 = (s: String) => println(s)
      
      class Scalable(d: Double) {
        def scale(/* What goes here? */) = ...
      }
      
      def scale(f: Double => Double) = f(d)
      
      val unscaled = (d: Double) => d
      
      class Scalable(d: Double) {
        val unscaled = (d: Double) => d
        def scale(f: Double => Double = unscaled) = f(d)
      }