首页 文章

Scala中方法和函数之间的区别

提问于
浏览
226

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

方法和功能不是一回事

但他没有解释任何有关它的事情 . 他想说什么?

6 回答

  • 33

    吉姆在his blog post中已经涵盖了这个,但我在这里发布简报以供参考 .

    首先,让我们看看Scala规范告诉我们的内容 . 第3章(类型)告诉我们函数类型(3.2.9)和方法类型(3.3.1) . 第4章(基本声明)涉及 Value 声明和定义(4.1),变量声明和定义(4.2)以及函数声明和定义(4.6) . 第6章(表达式)讲的是匿名函数(6.23)和方法值(6.7) . 奇怪的是,功能值在3.2.9中被说出一次,而在其他地方则没有 .

    Function Type (大致)是一种形式(T1,...,Tn)=> U,它是标准库中特征 FunctionN 的简写 . Anonymous FunctionsMethod Values 具有函数类型,函数类型可以用作值,变量和函数声明和定义的一部分 . 实际上,它可以是方法类型的一部分 .

    Method Typenon-value type . 这意味着有一个 no 值 - 没有对象,没有实例 - 带有方法类型 . 如上所述, Method Value 实际上有 Function Type . 方法类型是一个 def 声明 - 除了它的主体之外的所有关于_785622的声明 .

    Value Declarations and DefinitionsVariable Declarations and Definitionsvalvar 声明,包括类型和值 - 分别可以是 Function TypeAnonymous Functions or Method Values . 请注意,在JVM上,这些(方法值)是使用Java调用"methods"实现的 .

    Function Declarationdef 声明,包括类型和正文 . 类型部分是方法类型,主体是表达式或块 . 这也是在JVM上实现的,Java调用"methods" .

    最后, Anonymous FunctionFunction Type 的实例(即特征的实例 FunctionN ), Method Value 是同一个东西!区别在于方法值是从方法创建的,可以通过后缀下划线( m _ 是对应于"function declaration"( defm 的方法值),也可以通过称为eta-expansion的过程创建,这类似于方法的自动转换发挥作用 .

    这就是规范所说的,所以让我把它放在前面: we do not use that terminology! 它导致所谓的"function declaration"之间的混淆,这是程序的一部分(第4章 - 基本声明)和"anonymous function",这是一个表达式和"function type",这是一种类型 - 特征 .

    下面的术语,由经验丰富的Scala程序员使用,从规范的术语进行了一处更改: instead of saying function declaration, we say method . 甚至方法声明 . 此外,我们注意到值声明和变量声明也是实用的方法 .

    So, given the above change in terminology, here's a practical explanation of the distinction.

    函数是一个包含 FunctionX 特征之一的对象,例如 Function0Function1Function2 等 . 它也可能包括 PartialFunction ,它实际上扩展了 Function1 .

    让我们看看其中一个特征的类型签名:

    trait Function2[-T1, -T2, +R] extends AnyRef
    

    这个特性有一个抽象方法(它也有一些具体的方法):

    def apply(v1: T1, v2: T2): R
    

    这告诉我们所有人都应该了解它 . 函数有一个 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 类型签名 . 例如:

    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 _
    

    Scala将扩展它,假设 m 类型是 (List[Int])AnyRef into(Scala 2.7):

    val f = new AnyRef with Function1[List[Int], AnyRef] {
      def apply(x$1: List[Int]) = this.m(x$1)
    }
    

    在Scala 2.8上,它实际上使用 AbstractFunction1 类来减少类的大小 .

    请注意,无法转换其他方式 - 从函数到方法 .

    然而,方法有一个很大的优点(好吧,两个 - 它们可以稍快一点):它们可以接收类型参数 . 例如,虽然上面的 f 必须指定它接收的 List 的类型(在示例中为 List[Int] ), m 可以对其进行参数化:

    def m[T](l: List[T]): String = l mkString ""
    

    我认为这几乎涵盖了一切,但我很乐意补充这可以回答任何可能存在的问题 .

  • 3

    方法和函数之间的一个重大实际区别是 return 的含义 . return 只从方法返回 . 例如:

    scala> val f = () => { return "test" }
    <console>:4: error: return outside method definition
           val f = () => { return "test" }
                           ^
    

    从方法中定义的函数返回非本地返回:

    scala> def f: String = {                 
         |    val g = () => { return "test" }
         | g()                               
         | "not this"
         | }
    f: String
    
    scala> f
    res4: String = test
    

    而从本地方法返回只从该方法返回 .

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

    function可以使用参数列表调用函数以生成结果 . 函数具有参数列表,正文和结果类型 . 作为类,特征或单个对象的成员的函数称为方法 . 在其他函数内定义的函数称为局部函数 . 结果类型为Unit的函数称为过程 . 源代码中的匿名函数称为函数文字 . 在运行时,函数文字被实例化为称为函数值的对象 .

    Programming in Scala Second Edition. Martin Odersky - Lex Spoon - Bill Venners

  • 64

    假设你有一个清单

    scala> val x =List.range(10,20)
    x: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19)
    

    定义方法

    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
    

    用val定义函数

    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
    

    检查以下Tutorial,解释通过其他示例传递其他差异,例如使用方法Vs函数的diff的其他示例,使用函数作为变量,创建返回函数的函数

  • 11

    函数不支持参数默认值 . 方法呢 . 从方法转换为函数会丢失参数默认值 . (Scala 2.8.1)

  • 215

    有一篇很好的文章here,我的大部分描述都是从这篇文章中提取的 . 只是简单比较一下我理解的功能和方法 . 希望能帮助到你:

    Functions :它们基本上是一个对象 . 更确切地说,函数是具有apply方法的对象;因此,由于它们的开销,它们比方法慢一点 . 它类似于静态方法,因为它们独立于要调用的对象 . 一个简单的函数示例就像下面这样:

    val f1 = (x: Int) => x + x
    f1(2)  // 4
    

    除了将一个对象分配给另一个对象(如object1 = object2)之外,上面的行就没有了 . 实际上我们示例中的object2是一个匿名函数,左侧因此得到了一个对象的类型 . 因此,现在f1是一个对象(Function) . 匿名函数实际上是Function1 [Int,Int]的一个实例,它表示一个函数,其中一个参数类型为Int,返回值类型为Int . 在没有参数的情况下调用f1将为我们提供匿名函数的签名(Int => Int =)

    Methods :它们不是对象,而是分配给类的实例,即对象 . 与java中的方法或c中的成员函数完全相同(在this question的注释中指出Raffi Khatchadourian)等等 . 方法的一个简单示例就像下面这样:

    def m1(x: Int) = x + x
    m1(2)  // 4
    

    上面的行不是简单的值赋值,而是方法的定义 . 当您使用值2调用此方法时,如第二行,x将替换为2,结果将被计算,您将获得4作为输出 . 如果只是简单地编写m1就会出现错误,因为它是方法并且需要输入值 . 通过使用_,您可以将方法分配给类似下面的函数:

    val f2 = m1 _  // Int => Int = <function1>
    

相关问题