为什么在 scala 中允许 'val arr: Int => Int = Array(1,2,3)'

Why 'val arr: Int => Int = Array(1,2,3)' is allowed in scala

使用以下代码:

object Foo {
  val arr: Int => Int = Array(1,2,3)  
}

我们可以调用Foo.arr(1),然后得到2。但是,对象 Foo 中的 arr 应该是 Functionarr 是 Class WrappedArray$ofInt 的实例,显然不是 Function.
我想也许原因是 WrappedArray$ofIntimplements apply(i: Int),因为调用 Array(1,2,3)(1) 将被翻译成 Array(1,2,3).apply(1)。但是下面的代码会报错:

class Bar {
  def apply(i: Int): Int = {
    Array(1,2,3)(i)
  }
}
object Foo {
  val arr: Int => Int = new Bar()  //Type mismatch: 
                                   //    Required: Int => Int 
                                   //    Found: Bar
}

现在,为什么 Scala 允许 val arr: Int => Int = Array(1,2,3)

REPL 是探索此类情况的绝佳工具。

所以,让我们从代码开始:

val arr: Int => Int = Array(1,2,3)

Scala 中,唯一可行的方法是 Array[Int] <: Int => Int 或者是否存在从 Array[Int] 到子类型的隐式转换共 Int => Int

我们可以很容易地检查第一个不是这种情况:

implicitly[Array[Int] <:< Int => Int]}

产生:

error: No implicit view available from Array[Int] <:< Int => Int.

因此,它必须是第二个;我们也可以确认它在做:

implicitly[Array[Int] => (Int => Int)]
// val res: Array[Int] => (Int => Int) = $Lambda65/0x00000008406ff040@4dac40b

顺便说一句,如果我们将原始行粘贴到 REPL 中,我们会得到以下输出:

val foo: Int => Int = Array(1,2,3)
// val foo: Int => Int = ArraySeq(1, 2, 3)

所以我们已经可以看到转换发生了,结果是 ArraySeq[Int] (如果你检查 Scaladoc 你可以看到 class确实继承了Int => Int).


如果您想更深入地学习,可以使用 reify

import scala.reflect.runtime.universe.reify

reify { val foo: Int => Int = Array(1,2,3) }

产生以下输出:

val res: reflect.runtime.universe.Expr[Unit] =
Expr[Unit]({
  val foo: Function1[Int, Int] = Predef.wrapIntArray(Array.apply(1, 2, 3));
  ()
})

然后是 docs again we can see that it indeed returns an ArraySeq.