scala - 为什么案例模式匹配匿名函数可以有两个签名,并且具有神奇的调用站点兼容性

在 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/

相关文章:

python - 重复值 n 次,n 在一个数组中

python - 如何将字符串拆分为大小相等的部分?

reactjs - 使用 `new` 关键字作为参数的 useState

Haskell - 如何将矩阵(二维数组)分成几组

r - 按列计算唯一值

swift - iOS-14 netServiceBrowser.searchForServices

python - 变量和参数有什么区别

clojure - "let"的功能替代

python - 如何使用 numba 在 GPU 上推广快速矩阵乘法

swift - 在 RealityKit 中启用手势