在 Scala 中,模式匹配匿名函数一直让我感到惊讶。我刚刚发现了以下行为,我想知道如何理解它。
看来,匿名函数{ case (a, b) => (b, a) }
的参数签名既可以注解为单个元组参数,也可以注解为参数元组:
scala> ({ case (a, b) => (b, a) }: ((Int, Int)) => (Int, Int))
val res1: ((Int, Int)) => (Int, Int) = $Lambda$1160/0x0000000801127040@689fe2a3
scala> ({ case (a, b) => (b, a) }: (Int, Int) => (Int, Int))
val res2: (Int, Int) => (Int, Int) = $Lambda$1161/0x000000080106e840@1784d711
注意 res1
有一个元组参数,而 res2
有两个参数。这是为什么?这种行为是否在语言规范中定义? (对不起,还没有退房,目前对我来说似乎太密集了。)
此外,res1
函数神奇地接受了一个元组参数和两个调用点参数。
scala> res1((1,2))
val res3: (Int, Int) = (2,1)
scala> res1(1,2)
val res4: (Int, Int) = (2,1)
相比之下,res2
不接受元组参数:
scala> res2((1,2))
^
error: not enough arguments for method apply: (v1: Int, v2: Int): (Int, Int) in trait Function2.
Unspecified value parameter v2.
这是怎么回事?为什么 res1
可以根据需要更改其签名?
最佳答案
Is this behaviour defined in language specs?
根据open issue好像没有说明Spec doesn't mention automatic tupling #3583
What's going on here? Why
res1
can change its signature as it sees fit?
此功能称为自动双倍化。正如 Remove Two Warts: Auto-Tupling and Multi-Parameter Infix Operations #4311 中所讨论的那样,它可能会使某些调用站点更加自然。
(x, y) == z
z == ((x, y)) // !yuck
许多人主张删除/限制它,例如,Let’s drop auto-tupling .
编译器标志 -Xlint:adapted-args
可以在自动元组发生时发出警告,例如
➜ ~ scala
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_265).
Type in expressions for evaluation. Or try :help.
scala> def foo (x: (Int, Int)) = x
def foo(x: (Int, Int)): (Int, Int)
scala> foo (1,2)
val res0: (Int, Int) = (1,2)
scala> :replay -Xlint:adapted-args
replay> def foo (x: (Int, Int)) = x
def foo(x: (Int, Int)): (Int, Int)
replay> foo (1,2)
foo (1,2)
^
On line 2: warning: adapted the argument list to the expected 2-tuple: add additional parens instead
signature: foo(x: (Int, Int)): (Int, Int)
given arguments: 1, 2
after adaptation: foo((1, 2): (Int, Int))
def foo(x: (Int, Int)): (Int, Int)
val res0: (Int, Int) = (1,2)
另一个相关标志是-Xlint:multiarg-infix
, 例如
➜ ~ scala
Welcome to Scala 2.13.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_265).
Type in expressions for evaluation. Or try :help.
scala> def % (a: Int, b: Int) = (a,b)
def $percent(a: Int, b: Int): (Int, Int)
scala> :replay -Xlint:multiarg-infix
replay> def % (a: Int, b: Int) = (a,b)
^
warning: multiarg infix syntax looks like a tuple and will be deprecated
def $percent(a: Int, b: Int): (Int, Int)
https://stackoverflow.com/questions/63859326/