Scala 代码不会获取隐式 class 实例

Scala code will not pick up implicit class instance

为什么隐式没有被自动拾取?? 默认情况下,隐式 class 不会作为以下代码中的证据。

object temp {
  def main(args: Array[String]): Unit = {
    case class Foo(str: String)

    trait Special[A] {
      def getStr: String
    }

    implicit class SpecialFoo(x: Foo) extends Special[Foo] {
      def getStr = x.str
    }

    /* For the above SpecialFoo implicit class, I think the following is replaced by the compiler:
     * --------------------------------------------------------------------------------------------
       class SpecialFooClass(x: Foo) {
         def getStr: String = x.str
       }
       implicit def specialFooFunction(x: Foo): SpecialFooClass = new SpecialFooClass(x);
     * --------------------------------------------------------------------------------------------
     */

    def specialFunction[T: Special](thing: T): String = implicitly[Special[T]].getStr;

    // val wrapped = specialFunction(Foo("hi")) // Will not pick up the implicit SpecialFoo class, why??

    val foo = Foo("hi")
    val wrapped1: String = specialFunction(foo)(SpecialFoo(foo)) // But giving the evidence explicitly works!

    println(wrapped1)
  }
}

看来您在这里混淆了两个概念。

一方面,存在隐式转换,这意味着编译器会在任何时候将Foo类型的值转换为Special[Foo]类型的值它需要。这确实是您的 implicit class 声明的内容。

另一方面,

def specialFunction[T: Special](thing: T): String

的快捷方式
def specialFunction[T](thing: T)(implicit ev: Special[T]): String

这意味着 specialFunction 方法有两个参数。第二个参数是隐式的,这意味着如果你不显式传递它,编译器将尝试在隐式范围内找到它。但是,这里 没有 范围内的隐式 Special[Foo]。您拥有的是一种将 Foo 转换为 Special[Foo] 的隐式方法。

您在此处尝试使用的模式非常常见,但通常以另一种方式实现:

  trait Special[A] {
    def getStr(a: A): String
  }

  case class Foo(str: String)
  object Foo {
    implicit val special: Special[Foo] = new Special[Foo] {
      override def getStr(a: Foo) = a.str
    }
  }

  def specialFunction[T: Special](thing: T): String = 
    implicitly[Special[T]].getStr(thing)

  val foo = Foo("hi")
  println(specialFunction(foo))

在这里,我们不将 Foo 包装成 Special[Foo],而是将 Special[A] 视为一个单独的实体,知道如何从 String 中提取 String =24=].

注意:如果您使用的是 Scala 2.12,由于支持单个抽象方法(特征或抽象 类 仅包含单个抽象方法,比如 Special[A] 只有 getStr):

implicit val special: Special[Foo] = _.str

虽然@francoisr 的回答是一个有效的答案,但您似乎希望能够将对象传递给实现 Special[A] 接口的方法。您的代码将针对 specialFunction.

的以下定义进行编译
def specialFunction[T](thing: T)(implicit toSpecial: T => Special[T]): String = thing.getStr

这表示您需要将类型 T 转换为 Special[T],因此您可以调用 .getStr 方法。