在Scala中定义方法的九种方法?

Li *_*oyi 59 methods scala function

所以我一直试图通过各种方式来解决你在Scala中定义东西的方法,因为我对{}块的处理方式缺乏了解而变得复杂:

object NewMain extends Thing{

    def f1 = 10
    def f2 {10}
    def f3 = {10}
    def f4() = 10
    def f5() {10}
    def f6() = {10}
    def f7 = () => 10
    def f8 = () => {10}
    def f9 = {() => {10}}

    def main(args: Array[String]){
        println(f1)     // 10
        println(f2)     // ()
        println(f3)     // 10
        println(f4)     // 10
        println(f4())   // 10
        println(f5)     // ()
        println(f5())   // ()
        println(f6)     // 10
        println(f6())   // 10
        println(f7)     // <function0>
        println(f7())   // 10
        println(f8)     // <function0>
        println(f8())   // 10
        println(f9)     // <function0>
        println(f9())   // 10
    }

}
Run Code Online (Sandbox Code Playgroud)

据推测,其中一些是等价的,其中一些是其他人的语法糖,有些是我不应该使用的东西,但我不能为我的生活弄明白.我的具体问题是:

  • 它是如何,println(f2)以及 println(f5())unit?不是块中的最后一项10?它有什么不同println(f3()),哪个给出10

  • 如果println(f5)给出unit,不应该println(f5())是无效的,因为unit不是一个函数?这同样适用于println(f6)println(f6())

  • 所有这些打印10的国家: f1,f3,f4,f4(),f6,f6(),f7(),f8(),f9(),是他们之间有没有功能上的区别(在做什么的条款)或使用方面的差异(在何时应使用哪些词汇)?或者它们都相同?

non*_*unk 32

按顺序回答您的问题:

  • f2f5()返回Unit因为scala接受任何def没有" ="的任何函数返回Unit,无论块中的最后一项是什么.这是一件好事,因为否则定义一个不返回任何东西的函数就不会相当冗长.
  • println(f5())是有效的,即使它返回,Unit因为在scala中Unit是一个有效的对象,虽然不可否认你可以实例化.Unit.toString()例如,如果不是通常有用的声明,则是有效的.
  • 并非所有打印出来的版本10都是相同的.最重要的是f7,f8f9实际上是返回返回函数的函数10,而不是返回10直接.声明时def f8 = () => {10},您声明一个f8不带参数的函数,并返回一个不带参数的函数,并返回一个整数.当你调用时,println(f8)然后f8dilligently返回该功能给你.当你调用println(f8())它时返回该函数,然后立即调用它.
  • 功能f1,f3,f4,并且f6都在他们做什么,他们只是在风格上有所不同实质上具有同等.

正如"用户未知"所示,大括号仅对于作用范围很重要,并且不会对您的用例产生任何影响.

  • 最后一点是不正确的.Scala允许您在拨打电话时省略空白的parens.(你甚至可以`def foo()()()()()()()()= 10`并用`val x = foo`调用它.)@ LiHaoyi - 你正在寻找`foo _`.在这种情况下,存在多少个parens(零或一:`()=> Int`;更多产生一个curried chain`()=>()=> ...`. (2认同)
  • "因为在scala中`Unit`是一个有效的对象,虽然不可否认你可以实例化"你可以:`()`是类型`Unit`的唯一值. (2认同)

Spi*_*Pig 17

def f() {...}
Run Code Online (Sandbox Code Playgroud)

是的sytactic糖

def f(): Unit = {...}
Run Code Online (Sandbox Code Playgroud)

因此,如果省略"=",该方法将始终返回Unit类型的对象.在Scala中,方法和表达式总是返回一些东西.

def f() = 10
is sytactic sugar for
def f() = {
10
}
Run Code Online (Sandbox Code Playgroud)

如果你写def f()=()=> 10,它与写入相同

def f() = {
() => 10
}
Run Code Online (Sandbox Code Playgroud)

这意味着f正在返回一个函数对象.但是你可以写

val f = () => 10
Run Code Online (Sandbox Code Playgroud)

当你使用f()调用它时,它返回10个Function对象,并且在大多数情况下可以交换使用方法,但是存在一些语法差异.例如,当你写作

def f() = 10
println(f)
Run Code Online (Sandbox Code Playgroud)

你得到"10",但是当你写作

val f = () => 10
println(f)
Run Code Online (Sandbox Code Playgroud)

你得到

<function0>
Run Code Online (Sandbox Code Playgroud)

另一方面,当你有这个

val list = List(1,2,3)
def inc(x: Int) = x+1
val inc2 = (x: Int) => x+1
println(list.map(inc))
println(list.map(inc2))
Run Code Online (Sandbox Code Playgroud)

println都会打印相同的东西

List(2,3,4)
Run Code Online (Sandbox Code Playgroud)

在预期函数对象的位置使用方法的名称并且方法签名与预期函数对象的签名匹配时,它将自动转换.因此list.map(inc)scala编译器自动转换为

list.map(x => inc(x))
Run Code Online (Sandbox Code Playgroud)


Li *_*oyi 13

六年后,未来Scala的版本将在未来发布,事情有所改善:

这带来了我们定义一个函数的9种方法,以及将它们调用为7种定义函数的方法和10种调用它们的方法:

object NewMain extends Thing{

    def f1 = 10
    def f3 = {10}
    def f4() = 10
    def f6() = {10}
    def f7 = () => 10
    def f8 = () => {10}
    def f9 = {() => {10}}

    def main(args: Array[String]){
        println(f1)     // 10
        println(f3)     // 10
        println(f4())   // 10
        println(f6())   // 10
        println(f7)     // <function0>
        println(f7())   // 10
        println(f8)     // <function0>
        println(f8())   // 10
        println(f9)     // <function0>
        println(f9())   // 10
    }
}
Run Code Online (Sandbox Code Playgroud)

另见lampepfl/dotty2570 lampepfl/dotty#2571

因此,相对清楚哪种语法是可选的(例如{}s)以及哪些定义是等价的(例如def f4() = 10def f7 = () => 10).希望有一天,当Dotty/Scala-3.0发布时,学习该语言的新手将不再面对我六年前所做的混乱.