【问题标题】:Two ways of defining functions in Scala. What is the difference?在 Scala 中定义函数的两种方式。有什么区别?
【发布时间】:2011-06-27 22:06:44
【问题描述】:

这里有一个小 Scala 会话,它定义并尝试了一些函数:

scala> def test1(str: String) = str + str;    
test1: (str: String)java.lang.String

scala> test1("ab")
res0: java.lang.String = abab

效果很好。

scala> val test2 = test1
<console>:6: error: missing arguments for method test1 in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val test2 = test1
                   ^

哎呀。

scala> val test2 = test1 _
test2: (String) => java.lang.String = <function1>

scala> test2("ab")
res1: java.lang.String = abab

效果很好!

现在,我在折叠时看到了_ 语法(_ + _ 等)。所以据我了解_ 基本上意味着“一个论点”。所以test1 _ 基本上是指一个带有参数的函数,它被赋予test1"。但是为什么这与test1 不一样完全?为什么会有区别,如果我追加_?

所以我一直在探索……

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> test3("ab")
res2: java.lang.String = abab

scala> val test4 = test3
test4: (String) => java.lang.String = <function1>

在没有_ 的情况下它可以工作! defed 函数和 valed 函数有什么区别?

【问题讨论】:

  • 雷克斯,我会为你节省一些时间。您已经在 2010 年 1 月 27 日的邮件列表中回答了这个问题。这是一个很好的反应,所以我把它加了书签。 scala-programming-language.1934581.n4.nabble.com/…
  • 我认为在 Scala 中使用术语“函数”/“定义函数”存在一些令人遗憾的混淆。甚至 在 Scala 中编程 都说 def 定义了一个函数,但这并不完全正确,具体取决于您对“函数”的定义。 IE。方法返回的结果是其参数的函数,但该方法不是函数值函数对象。区分“函数”一词的这两种用法可能会有所帮助。
  • 阅读我在 10 年 4 月的类似问题中的retronyms 答案。 stackoverflow.com/questions/2720486/… - (ps,我QRd你的头像,很有趣!)
  • 简而言之 - 功能与方法

标签: function scala currying


【解决方案1】:

def 在周围的对象/类/特征中声明一个方法,类似于在 Java 中定义方法的方式。您只能在其他对象/类/特征中使用defs。在 REPL 中,您看不到周围的对象,因为它是“隐藏的”,但它确实存在。

您不能将def 分配给一个值,因为def 不是一个值 - 它是对象中的一个方法。

(x: T) =&gt; x * x 声明并实例化了一个函数对象,它存在于运行时。函数对象是扩展 FunctionN 特征的匿名类的实例。 FunctionN 特征带有 apply 方法。 apply 这个名字很特别,因为它可以省略。表达式f(x) 被脱糖为f.apply(x)

底线是 - 由于函数对象是存在于堆上的运行时值,因此您可以将它们分配给值、变量和参数,或者从方法中将它们作为返回值返回。

为了解决将方法分配给值的问题(这很有用),Scala 允许您使用占位符从方法创建函数对象。上面示例中的表达式 test1 _ 实际上围绕方法 test1 创建了一个包装函数 - 它等效于 x =&gt; test1(x)

【讨论】:

  • 简单而干净的答案,+1
【解决方案2】:

下划线在不同的上下文中表示不同的意思。但它总是可以被认为是可以放在这里的东西,但不需要命名

当代替参数应用时,效果是将方法提升为函数。

scala> def test1(str: String) = str + str; 
test1: (str: String)java.lang.String

scala> val f1 = test1 _
f1: (String) => java.lang.String = <function1>

注意,方法变成了函数类型(String) => String。

Scala 中方法和函数的区别在于方法类似于传统的 Java 方法。您不能将它们作为值传递。然而,函数本身就是值,可以用作输入参数和返回值。

提升可以走得更远:

scala> val f2 = f1 _
f2: () => (String) => java.lang.String = <function0>

提升此功能会导致另一个功能。这次的类型 () => (String) => (String)

据我所知,这种语法等同于用下划线显式替换所有参数。例如:

scala> def add(i: Int, j: Int) = i + j
add: (i: Int,j: Int)Int

scala> val addF = add(_, _)
addF: (Int, Int) => Int = <function2>

scala> val addF2 = add _    
addF2: (Int, Int) => Int = <function2>

【讨论】:

    【解决方案3】:

    def'ed 函数和 val'ed 函数之间没有区别:

    scala> def test1 = (str: String) => str + str
    test1: (String) => java.lang.String
    
    scala> val test2 = test1
    test2: (String) => java.lang.String = <function1>
    
    scala> val test3 = (str: String) => str + str
    test3: (String) => java.lang.String = <function1>
    
    scala> val test4 = test2
    test4: (String) => java.lang.String = <function1>
    

    看到了吗?这些都是函数,由它们拥有的X =&gt; Y类型表示。

    scala> def test5(str: String) = str + str
    test5: (str: String)java.lang.String
    

    你看到X =&gt; Y 类型了吗?如果你这样做,去看眼科医生,因为没有。这里的类型是(X)Y,常用来表示一个方法

    其实test1test2test3test4都是方法,都是返回函数。 test5 是一个返回 java.lang.String 的方法。此外,test1test4 不带参数(无论如何,只有 test1 可以),而 test5 可以。

    所以,区别很简单。在第一种情况下,您尝试将方法分配给 val,但没有填写方法采用的参数。所以它失败了,直到你添加了一个尾随下划线,这意味着把我的方法变成一个函数

    在第二个例子中,你有一个函数,所以你不需要做任何其他事情。

    方法不是函数,反之亦然。函数是FunctionN 类之一的对象。方法是与对象关联的某些代码的句柄。

    在 Stack Overflow 上查看有关方法与函数的各种问题。

    【讨论】:

    • 我喜欢这个答案。一些后续问题:1) 你看到 X => Y 类型了吗?第二行怎么样?难道不是X =&gt; Y,因为它在String 周围有()? (否则我必须在黄页中寻找一位生殖学家。)2)从你的描述中,我觉得函数比方法更通用,我可以使用你的@到处都是 987654341@-notation 而不是 test5-notation?缺点是什么?
    • @Synesso 是的,不,有点。它是 REPL 对假设方法类型的表示。
    • @aioobe 第二行不是X =&gt; Y,因为没有=&gt;。函数比方法慢,而且它们不能接收类型参数——这在 Stack Overflow 的其他地方已经讨论过了。
    • scala&gt; val test4 = test2 是志愿者,还是你的意思是 val test4 = test3
    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 2013-08-07
    • 2014-11-21
    • 1970-01-01
    相关资源
    最近更新 更多