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

时间:2011-11-28 23:21:20

标签: scala methods 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
    }

}

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

  • println(f2)println(f5())给出unit的情况如何?不是块10中的最后一项吗?它与println(f3())的不同之处在于10

  • 如果println(f5)提供unit,则println(f5())不应该无效,因为unit不是函数?这同样适用于println(f6)println(f6())

  • 所有打印10的人: f1f3f4f4()f6f6()f7()f8(),{{ 1}}, 它们之间是否有任何功能差异(就它的作用而言)或使用差异(就何时使用而言)?或者它们都是等价的?

4 个答案:

答案 0 :(得分:32)

按顺序回答您的问题:

  • f2f5()返回Unit,因为scala会将没有“def”的任何=作为返回Unit的函数,无论块中的最后一项是什么。这是一件好事,因为否则定义一个不返回任何内容的函数就不会相当冗长。
  • println(f5())有效,即使它返回Unit,因为在scala中Unit是一个有效的对象,但不可否认,它可以实例化。例如,Unit.toString()是有效的,如果不是通常有用的声明。
  • 并非所有打印出10的版本都相同。最重要的是,f7f8f9实际上是返回返回10的函数的函数,而不是直接返回10。当您声明def f8 = () => {10}时,您声明一个不带参数的函数f8并返回一个不带参数的函数并返回一个整数。当您调用println(f8)时,f8会立即将该函数返回给您。当你调用println(f8())时,它会返回该函数,然后立即调用它。
  • 函数f1f3f4f6在所做的事情上基本相同,只是在风格方面有所不同。

正如“用户未知”所示,大括号仅对于作用范围很重要,并且对您的用例没有任何影响。

答案 1 :(得分:16)

def f() {...}

的糖

def f(): Unit = {...}

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

def f() = 10
is sytactic sugar for
def f() = {
10
}

如果你写def f()=()=&gt; 10,它与写作相同

def f() = {
() => 10
}

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

val f = () => 10

当你用f()调用它时,它返回10 在大多数情况下,函数对象和方法可以互换使用,但存在一些语法差异。 例如 当你写

def f() = 10
println(f)

你得到“10”,但是当你写下

val f = () => 10
println(f)

你得到了

<function0>

另一方面,当你有这个

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))

两个println都会打印相同的东西

List(2,3,4)

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

list.map(x => inc(x))

答案 2 :(得分:12)

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

这带来了我们定义一个函数的9种方法和15种将它们调用为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
    }
}

另请参阅lampepfl/dotty2570 lampepfl/dotty#2571

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

答案 3 :(得分:4)

def f1 = 10    
def f2 {10}    

第二种形式不使用作业。因此,您可以将其视为一个程序。它并不意味着返回一些东西,因此返回Unit,即使最后一个语句可以用来返回特定的东西(但它可能是一个if语句,只能在一个分支中有特定的东西)。

def f1 = 10    
def f3 = {10}  

这里你不需要括号。例如,如果定义了val,则需要它们,因此该val的范围仅限于封闭块。

def sqrGtX (n:Int, x: Int) = {
  val sqr = n * n
  if (sqr > x) 
    sqr / 2 
  else x / 2 
}  

这里需要花括号来定义val sqr。如果val在内部分支中声明,则花括号不需要位于方法的顶级:

def foo (n:Int, x: Int) = 
  if (n > x) {
    val bar = x * x + n * n
    println (bar) 
    bar - 2  
  } else x - 2 

为了进一步研究两个方法返回相同的结果,您可以编译它们并比较字节码。两个二进制相同的方法将是相同的。