首页 文章

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

提问于
浏览
55

所以我一直试图通过各种方式来解决你在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)unitprintln(f5()) 不应该无效,因为 unit 不是函数?这同样适用于 println(f6)println(f6())

  • 在所有打印10: f1f3f4f4()f6f6()f7()f8()f9() 中,它们之间是否有任何功能差异(就其作用而言)或使用差异(就何时而言)我应该用哪个)?或者它们都相同?

4 回答

  • 16

    按顺序回答您的问题:

    • f2f5() 返回 Unit 因为scala将任何 def 没有“ = ”作为返回 Unit 的函数,无论块中的最后一项是什么 . 这是一件好事,因为否则定义一个不返回任何东西的函数就不会相当冗长 .

    • println(f5()) 有效,即使它返回 Unit 因为在scala中 Unit 是一个有效的对象,但不可否认,你可以实例化它 . 例如, Unit.toString() 是有效的,如果不是通常有用的语句 .

    • 并非所有打印出来的版本_1566336都是相同的 . 最重要的是, f7f8f9 实际上是返回返回 10 的函数的函数,而不是直接返回 10 . 当您声明 def f8 = () => {10} 时,您声明一个不带参数的函数 f8 并返回一个不带参数的函数并返回一个整数 . 当你调用 println(f8) 然后 f8 dilligently返回该功能给你 . 当你调用 println(f8()) 它返回函数,然后立即调用它 .

    • 函数 f1f3f4f6 在它们的作用方面基本上是等价的,它们仅在样式方面有所不同 .

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

  • 31
    def f() {...}
    

    是的sytactic糖

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

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

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

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

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

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

    val f = () => 10
    

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

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

    六年后,未来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
        }
    }
    

    另见lampepfl/dotty2570 lampepfl/dotty#2571

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

  • 10
    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
    

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

相关问题