以下在Scala中编写函数的方法有什么不同?
我是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 + ",") }
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 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
。这比在案例1中直接调用普通方法要慢。二,apply(节点)
- 作为
:这声明了一个变量并创建了一个函数对象,如3所示,但函数对象只创建一次。在大多数情况下,使用它来调用函数对象比简单的方法调用慢(JIT可能不会内联),但至少不会重新创建对象。如果要避免有人重新分配变量var
,请改用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)
}