带有隐式参数的函数在没有它的情况下也能工作。为什么?

Function with an implicit parameter works without it. Why?

使用 Scala REPL,我定义了一个函数,该函数将 Int 作为其第一个参数,并将具有此签名 Int => Int 的函数作为第二个 implicit参数:

scala> def doer(i: Int)(implicit a: Int => Int): Int = a(i)
doer: (i: Int)(implicit a: Int => Int)Int

为什么 运行 这个函数在不提供隐式参数的情况下工作?

scala> doer(4)
res1: Int = 4

隐含的Int to Int函数从何而来? REPL 报告没有定义隐式:

scala> :impl
No implicits have been imported other than those in Predef.

scala.Predef 中定义了一堆隐式,无需明确限定即可在所有 Scala 编译单元中访问,其中之一是

implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer]

如果您查看 Predef 源代码,可能会看到很多隐式函数。编译器只会选择一个兼容的。

一些示例:

  implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps.ofBoolean(xs)
  implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte]          = new ArrayOps.ofByte(xs)
  implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char]          = new ArrayOps.ofChar(xs)
  implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double]    = new ArrayOps.ofDouble(xs)
  implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float]       = new ArrayOps.ofFloat(xs)
  implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int]             = new ArrayOps.ofInt(xs)
  implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long]          = new ArrayOps.ofLong(xs)
  implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T]    = new ArrayOps.ofRef[T](xs)
  implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short]       = new ArrayOps.ofShort(xs)
  implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit]          = new ArrayOps.ofUnit(xs)

  // "Autoboxing" and "Autounboxing" ---------------------------------------------------

  implicit def byte2Byte(x: Byte)           = java.lang.Byte.valueOf(x)
  implicit def short2Short(x: Short)        = java.lang.Short.valueOf(x)
  implicit def char2Character(x: Char)      = java.lang.Character.valueOf(x)
  implicit def int2Integer(x: Int)          = java.lang.Integer.valueOf(x)
  implicit def long2Long(x: Long)           = java.lang.Long.valueOf(x)
  implicit def float2Float(x: Float)        = java.lang.Float.valueOf(x)
  implicit def double2Double(x: Double)     = java.lang.Double.valueOf(x)
  implicit def boolean2Boolean(x: Boolean)  = java.lang.Boolean.valueOf(x)

  implicit def Byte2byte(x: java.lang.Byte): Byte             = x.byteValue
  implicit def Short2short(x: java.lang.Short): Short         = x.shortValue
  implicit def Character2char(x: java.lang.Character): Char   = x.charValue
  implicit def Integer2int(x: java.lang.Integer): Int         = x.intValue
  implicit def Long2long(x: java.lang.Long): Long             = x.longValue
  implicit def Float2float(x: java.lang.Float): Float         = x.floatValue
  implicit def Double2double(x: java.lang.Double): Double     = x.doubleValue
  implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.booleanValue

隐式就是为此目的而设计的。编译器将搜索是否有任何隐式定义对象可用。如果找到,则将使用它们。 scala 提供了许多隐式定义对象。您还可以将自定义对象定义为隐式,如果它们在您的代码范围内,将被使用。

查看文档 https://docs.scala-lang.org/tour/implicit-parameters.html

doer 之所以有效,是因为它接受隐式参数,因此在 Predef 中可用。 Predef 自动导入到 Scala 作用域。看起来使用的函数是 int2Integer

Predef 包含一个 implicit evidence that one type is a subtype of another: A <:< B。每种类型都是其自身的子类型,因此 implicitly[Int <:< Int] 有效。 <:< class 扩展函数 A => B。这就是 implicitly[Int => Int] 也有效的原因。

Intjava.lang.Integer 是不同的东西,没有任何子类型关系,所以这些 int2Integer 隐式与它无关。

如果您有最新 Scala 版本的 REPL,您可以输入

scala> doer(4) //print

然后按 tab 键而不是 enter。它将向您显示代码的脱糖版本 doer(4)(scala.Predef.$conforms[Int]),其中所有隐式都已显式填充。