【问题标题】:Function with an implicit parameter works without it. Why?带有隐式参数的函数没有它也可以工作。为什么?
【发布时间】:2018-04-24 03:53:45
【问题描述】:

使用 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 to Int 函数从何而来? REPL 报告没有定义隐式:

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

【问题讨论】:

  • 为了避免这种问题,我只允许implicit 参数使用至少一种由我的代码定义的类型。这意味着不存在与其他库中定义的 implicit 值混淆的危险。

标签: scala implicit


【解决方案1】:

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

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

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

scala> doer(4) //print

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

【讨论】:

    【解决方案2】:

    在 scala.Predef 中定义了许多隐式,它们可以在所有 Scala 编译单元中访问,无需显式限定,其中之一是

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

    【讨论】:

      【解决方案3】:

      如果您查看 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
      

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-03
          • 1970-01-01
          • 2014-01-17
          • 1970-01-01
          • 2021-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多