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

所以我一直试图通过各种方式来解决你在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())有什么不同?

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

  • 在所有打印10: f1f3f4f4()f6f6()f7()f8()f9()之间,它们之间是否有任何function上的区别)或使用差异(根据什么时候我应该使用哪个)? 还是它们都是等同的?

按顺序回答您的问题:

  • f2f5()返回Unit因为scala在没有“ = ”的情况下使用任何def是一个返回Unit的函数,而不pipe块中的最后一项是什么。 这是一件好事,因为否则定义一个不返回任何东西的函数将不是很繁琐。
  • println(f5())是有效的,即使它返回Unit因为在scala Unit是一个有效的对象,虽然承认不是你可以实例化。 Unit.toString()是一个有效的(如果不是通常有用的话)语句。
  • 并不是所有打印出来的版本都是一样的。 最重要的是, f7f8f9实际上是返回10函数,而不是直接返回10 。 当你声明def f8 = () => {10} ,你声明了一个不带参数的函数f8 ,并且返回一个不带参数并返回一个整数的函数。 当你调用println(f8)然后f8将该函数返回给你。 当你调用println(f8())它返回函数,然后立即调用它。
  • functionf1f3f4f6在function上基本上是相同的,它们只是在风格上有所不同。

正如“用户未知”所表示的那样,大括号只是用于范围界定的目的,在这里您的用例没有任何区别。

 def f() {...} 

是以sytoctic糖为

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

所以,如果你省略了“=”,那么方法总是返回一个Unittypes的对象。 在斯卡拉,方法和expression式总是返回一些东西。

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

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

  • 定义f2f5已被删除为“ 过程语法 ”
  • 无需调用f4 f5f6 已被删除 。

这就把我们定义一个函数的方法和十五种方法叫做定义一个函数的方法和十种调用方法:

 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发布的时候,学习这门语言的新手将不再面对六年前我所做的同样的困惑。

 def f1 = 10 def f2 {10} 

第二种forms不使用任务。 所以你可以把它想成一个程序。 这并不意味着要返回一些东西,因此返回单元,即使最后一个语句可以用来返回特定的东西(但它可能是一个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 

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