Function Scala中方法和函数的区别

Function Scala中方法和函数的区别,function,scala,methods,Function,Scala,Methods,我读了(另一次Scala之旅的一部分)。他在那篇文章中说: 方法和函数不是一回事 但他没有解释这件事。他想说什么?方法和函数之间的一大实际区别是返回的含义返回仅从方法返回。例如: scala> val f = () => { return "test" } <console>:4: error: return outside method definition val f = () => { return "test" }

我读了(另一次Scala之旅的一部分)。他在那篇文章中说:

方法和函数不是一回事


但他没有解释这件事。他想说什么?

方法和函数之间的一大实际区别是返回的含义<代码>返回仅从方法返回。例如:

scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
       val f = () => { return "test" }
                       ^
val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
  case i: Int => "Int"
  case d: Double => "Double"
  case o => "Other"
}
而从本地方法返回只从该方法返回

scala> def f2: String = {         
     | def g(): String = { return "test" }
     | g()
     | "is this"
     | }
f2: String

scala> f2
res5: String = is this

方法和函数之间一个很大的实际区别是
return
的含义<代码>返回仅从方法返回。例如:

scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
       val f = () => { return "test" }
                       ^
val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
  case i: Int => "Int"
  case d: Double => "Double"
  case o => "Other"
}
而从本地方法返回只从该方法返回

scala> def f2: String = {         
     | def g(): String = { return "test" }
     | g()
     | "is this"
     | }
f2: String

scala> f2
res5: String = is this

Jim对此已经做了很多介绍,但我在这里发布了一个简报供参考

首先,让我们看看Scala规范告诉我们什么。第3章(类型)告诉我们函数类型(3.2.9)和方法类型(3.3.1)。第4章(基本声明)介绍了值声明和定义(4.1)、变量声明和定义(4.2)以及函数声明和定义(4.6)。第6章(表达式)谈到匿名函数(6.23)和方法值(6.7)。奇怪的是,函数值在3.2.9中只提到过一次,其他地方没有提到

A函数类型是(大致)一种形式(T1,…,Tn)=>U的类型,是标准库中trait
Function n
的缩写匿名函数方法值具有函数类型,函数类型可以用作值、变量和函数声明和定义的一部分。事实上,它可以是方法类型的一部分

方法类型非值类型。这意味着没有方法类型的值-没有对象,没有实例。如上所述,方法值实际上有一个函数类型。方法类型是一个
def
声明-关于
def
的所有内容,除了它的主体

值声明和定义变量声明和定义
val
var
声明,包括类型和值-分别可以是函数类型匿名函数或方法值。注意,在JVM上,这些(方法值)是用Java所称的“方法”实现的

函数声明
def
声明,包括类型和主体。类型部分是方法类型,主体是表达式或块。这也在JVM上实现,Java称之为“方法”

最后,匿名函数函数类型的实例(即trait
Function的实例
),而方法值也是一样的!区别在于,方法值是从方法中创建的,可以通过后固定下划线(
m
是对应于“函数声明”(
def
m
)的方法值,也可以通过称为eta扩展的过程来创建,该过程类似于从方法到函数的自动转换

这就是规范所说的,所以让我把这个放在前面:我们不使用这个术语它导致了所谓的“函数声明”(它是程序的一部分)(第4章——基本声明)和“匿名函数”(它是一个表达式)与“函数类型”(它是一种类型——一种特征)之间的太多混淆

下面有经验的Scala程序员使用的术语对规范的术语做了一个更改:我们说的不是函数声明,而是方法。甚至方法声明。此外,我们注意到值声明和变量声明也是用于实际目的的方法

因此,鉴于上述术语的变化,这里是对区别的实际解释。

函数是包含
FunctionX
特征之一的对象,例如
Function0
Function1
Function2
,等等。它可能还包括
PartialFunction
,它实际上扩展了
Function1

让我们看看这些特征之一的类型签名:

trait Function2[-T1, -T2, +R] extends AnyRef
这种特性有一种抽象方法(也有一些具体方法):

这告诉了我们关于它的一切。函数有一个
apply
方法,该方法接收类型为T1、T2、…、TN的N个参数,并返回类型为
R
的内容。它在接收的参数上是反向变量,在结果上是协变量

这种差异意味着
Function1[Seq[T],String]
Function1[List[T],AnyRef]
的子类型。作为一个子类型意味着它可以用来代替它。我们可以很容易地看到,如果我要调用
f(List(1,2,3))
并期望返回
AnyRef
,那么上面两种类型中的任何一种都可以工作

现在,一个方法和一个函数有什么相似之处?如果
f
是一个函数,而
m
是作用域的一个局部方法,那么两者都可以这样调用:

val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))
这些调用实际上是不同的,因为第一个调用只是一个语法糖。Scala将其扩展为:

val o1 = f.apply(List(1, 2, 3))
当然,这是对对象
f
的方法调用。函数还有其他语法优势:函数文本(实际上是其中两个)和
(T1,T2)=>R
类型签名。例如:

scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
       val f = () => { return "test" }
                       ^
val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
  case i: Int => "Int"
  case d: Double => "Double"
  case o => "Other"
}
方法和函数之间的另一个相似之处是前者可以很容易地转换为后者:

val f = m _
假设
m
类型为
(List[Int])AnyRef
,Scala将其扩展为(Scala 2.7):

在Scala 2.8上,它实际上使用了
AbstractFunction1
scala> def m1(i:Int)=i+2
m1: (i: Int)Int
scala> (i:Int)=>i+2
res0: Int => Int = <function1>

scala> x.map((x)=>x+2)
res2: List[Int] = List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)
scala> m1(2)
res3: Int = 4
scala> val p =(i:Int)=>i+2
p: Int => Int = <function1>
 scala> p(2)
    res4: Int = 4

scala> p
res5: Int => Int = <function1>
scala> m1
<console>:9: error: missing arguments for method m1;
follow this method with `_' if you want to treat it as a partially applied function
val f1 = (x: Int) => x + x
f1(2)  // 4
def m1(x: Int) = x + x
m1(2)  // 4
val f2 = m1 _  // Int => Int = <function1>
def fmet[T](x: List[T]) = x.map(e => (e, e))
val ffun = [T] => (x: List[T]) => x.map(e => (e, e))
def gmet[T](implicit num: Numeric[T]): T = num.zero
val gfun: [T] => Numeric[T] ?=> T = [T] => (using num: Numeric[T]) => num.zero
class A { class B }
def hmet(a: A): a.B = new a.B
val hfun: (a: A) => a.B = hmet