带有隐式参数的函数可以在没有它的情为什么?

时间:2018-04-24 03:53:46

标签: scala implicit

使用Scala REPL,我定义了一个函数,它将Int作为其第一个参数,并使用此签名Int => Int作为第二个隐式参数:

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到Int函数的隐式Int来自何处? REPL报告没有定义任何含义:

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

4 个答案:

答案 0 :(得分:2)

Predef包含implicit evidence,其中一种类型是另一种类型的子类型:A <:< B。每种类型都是自身的子类型,因此implicitly[Int <:< Int]起作用。此<:<类扩展了函数A => B。这就是implicitly[Int => Int]也起作用的原因。

然而,

Intjava.lang.Integer是不同的事物,没有任何子类型关系,所以这些int2Integer暗示与它无关。

如果你有最近Scala版本的REPL,你可以输入

scala> doer(4) //print

然后按Tab键而不是输入。它将向您显示代码的desugared版本doer(4)(scala.Predef.$conforms[Int]),并明确填写所有含义。

答案 1 :(得分:0)

在scala.Predef中定义了大量的implicits,它们可以在没有明确限定的所有Scala编译单元中访问,其中一个是

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

答案 2 :(得分:0)

如果检查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

答案 3 :(得分:0)

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

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

doer 有效,因为它接受隐式参数,因此它在Predef中可用。 Predef会自动导入scala范围。看起来使用的函数是 int2Integer