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
方法。
为什么隐式没有被自动拾取?? 默认情况下,隐式 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
方法。