我是Scala的初学者,看到了几种不同的调用方法的语法。有些很好,比如对于没有参数的方法可以忽略括号,或者像下面这样省略掉点号:
1 to 10
但有一些真的让我感到困惑,例如:
breakable { ... }
这只是一个方法调用,对吗?我还能为多个参数或不是无参函数的参数这样做吗?
谢谢
调用方法有两种标准方式:
obj.method(params) // dot notation
obj method (params) // operator notation
上述内容可以通过以下方式进行修改:
params
是单个参数,则可以使用{}
替换()
。params
是单个参数,并且您正在使用运算符符号,那么可以省略括号。method
不需要参数,则可以省略(params)
(即删除空的()
)。method
以:
结尾,则实际上将绑定到右边的操作符符号。也就是说,(params) method_: obj
等同于obj.method_:(params)
。obj . method ( params )
或将.method(params)
写在下一行,就像调用链接一样,还可以从操作符符号中移除空格,例如a+b
。还有一些关于元组推断的东西,但我尽量避免使用它,所以对准确的规则不太确定。
然而,这些都无法解释您困惑的示例。在我解释之前,我想展示一些语法糖,也可以用于调用方法:
obj(params) // equivalent to obj.apply(params)
obj.x = y // equivalent to obj.x_=(y), if obj.x also exists
obj(x) = y // equivalent to obj.update(x, y)
obj op= y // equivalent to obj = obj op y, if op is symbolic
~obj // equivalent to obj.unary_~; also for !, + and -, but no other symbol
好的,现在让我们来看看你提供的示例。人们可以通过稳定值进行成员导入。Java可以使用其静态导入来导入静态方法,但Scala有一种更通用的机制:从包、对象或常见实例中导入没有区别:它会引入类型成员和值成员。方法属于后者。
因此,假设您有一个val a = 2
,并且您执行import a._
。这将使所有Int
方法进入范围,因此您可以直接调用它们。您不能执行+(2)
,因为那将被解释为对unary_+
的调用,但您可以调用*(4)
,例如:
scala> val a = 2
a: Int = 2
scala> import a._
import a._
scala> *(4)
res16: Int = 8
现在,这是规则。你可以调用
method(params)
如果:
method
已经被导入到作用域中。请注意,还存在优先级问题。如果您编写 obj method(params)
,Scala将假定 method
属于 obj
,即使它已被导入到作用域中。
()
和{}
在表达式内有不同的含义。也就是说,2 * (3 + 4)
和2 * {3 + 4}
的结果相同,但它们是不同的东西。你只能在括号内放置表达式,而将定义和语句放在花括号内,在其中最后一个语句的值是表达式的值(花括号本身是一个表达式)。f(...)
可以替换为 f{...}
的原因只是为了让人们不必写 f({...})
。这使人们能够编写看起来本地化的“用户”控制结构。 - Daniel C. Sobral如果我们进行脱糖处理,那么我们将得到:
breakable({ ... })
这个匹配了签名
breakable: (op: ⇒ Unit): Unit
并且使用所谓的按名称调用参数(你可以将其看作将一块代码作为参数传递)
此外,scala还允许您编写以下内容:
scala> def foo (op1: => Unit)(op2: => Unit) = {op1;op2;}
foo: (op1: => Unit)(op2: => Unit)Unit
scala> foo { println(1) } { println(2) }
1
2
上面是柯里化函数的示例。
{...}
)部分还是我们没有在方法前缀中加入对象/类名的事实? - Nicolas