首页 文章

两种在Scala中定义函数的方法 . 有什么不同?

提问于
浏览
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

效果很好!

现在,我在折叠时看到了 _ 语法( _ + _ 等) . 据我了解 _ 基本上意味着"an argument" . 所以 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>

这里没有 _def ed函数和 val ed函数之间的区别是什么?

3 回答

  • 53

    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 => Y 类型表示 .

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

    你看到 X => Y 类型了吗?如果你这样做,去看眼科医生,因为没有 . 这里的类型是 (X)Y ,通常用于表示方法 .

    实际上, test1 ,_ 283833test3test4 都是返回函数的方法 . test5 是一个返回 java.lang.String 的方法 . 此外, test1test4 不接受参数(无论如何只能 test1 ),而 test5 .

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

    在第二个示例中,您有一个函数,因此您不需要执行任何其他操作 .

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

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

  • 58

    def 在周围的对象/类/特征中声明一个方法,类似于在Java中定义方法的方式 . 您只能在其他对象/类/特征中使用 def . 在REPL中,您无法看到周围的对象,因为它是"hidden",但它确实存在 .

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

    (x: T) => x * x 声明并实例化 function object ,它在运行时存在 . 函数对象是扩展 FunctionN 特征的匿名类的实例 . FunctionN 特征带有 apply 方法 . 名称 apply 是特殊的,因为它可以省略 . 表达式 f(x) 被贬低为 f.apply(x) .

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

    为了解决为值分配方法的问题(这可能很有用),Scala允许您使用占位符字符从方法创建函数对象 . 上面示例中的表达式 test1 _ 实际上围绕方法 test1 创建了一个包装函数 - 它相当于 x => test1(x) .

  • 11

    下划线在不同的上下文中意味着不同的东西 . 但它总是可以被认为是会在这里发生的事情,但不需要被命名 .

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

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

    注意,该方法已成为type(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>
    

相关问题