Scala 类型类隐式解析
Scala typeclasses implicit resolution
(Scala 2.11.8)
考虑以下代码:
object ScalaTest extends App {
class Wrapper {
import Wrapper._
def init(): Unit = {
// "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles again!
printWithTC(132)
}
}
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit object IntTC extends TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
(new Wrapper).init()
}
关于这段代码我有一堆问题:
- 为什么
IntTC
一开始没有解决?
- 为什么用一次就编译成功? (如果您注释掉第一次调用,代码有效)
- 类型类隐式应放在哪里才能正确解析?
在使用之前定义隐式。
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit object IntTC extends TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
class Wrapper {
import Wrapper._
def init(): Unit = {
// "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles again!
printWithTC(132)
}
}
(new Wrapper).init()
使用具有显式 return 类型的 val
。参见 https://github.com/scala/bug/issues/801 and https://github.com/scala/bug/issues/8697(以及其他)。
隐式对象与具有推断 return 类型的隐式 vals 和 defs 具有相同的问题。至于你的第二个问题:当 IntTC
被显式使用时,你会强制编译器对其进行类型检查,因此在那之后它的类型是已知的并且可以通过隐式搜索找到。
class Wrapper {
import Wrapper._
def init(): Unit = {
// Compiles
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles
printWithTC(132)
}
}
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit val IntTC: TC[Int] = new TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
如果你真的希望你的隐式像对象一样被延迟评估,你可以使用具有显式类型的 implicit lazy val
。
(Scala 2.11.8)
考虑以下代码:
object ScalaTest extends App {
class Wrapper {
import Wrapper._
def init(): Unit = {
// "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles again!
printWithTC(132)
}
}
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit object IntTC extends TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
(new Wrapper).init()
}
关于这段代码我有一堆问题:
- 为什么
IntTC
一开始没有解决? - 为什么用一次就编译成功? (如果您注释掉第一次调用,代码有效)
- 类型类隐式应放在哪里才能正确解析?
在使用之前定义隐式。
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit object IntTC extends TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
class Wrapper {
import Wrapper._
def init(): Unit = {
// "could not find implicit value for parameter tc: ScalaTest.Wrapper.TC[Int]"
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles again!
printWithTC(132)
}
}
(new Wrapper).init()
使用具有显式 return 类型的 val
。参见 https://github.com/scala/bug/issues/801 and https://github.com/scala/bug/issues/8697(以及其他)。
隐式对象与具有推断 return 类型的隐式 vals 和 defs 具有相同的问题。至于你的第二个问题:当 IntTC
被显式使用时,你会强制编译器对其进行类型检查,因此在那之后它的类型是已知的并且可以通过隐式搜索找到。
class Wrapper {
import Wrapper._
def init(): Unit = {
// Compiles
printWithTC(123)
// Compiles
printWithTC(123)(IntTC)
// Compiles
printWithTC(132)
}
}
object Wrapper {
trait TC[A] {
def text(a: A): String
}
implicit val IntTC: TC[Int] = new TC[Int] {
override def text(a: Int) = s"int($a)"
}
def printWithTC[A](a: A)(implicit tc: TC[A]): Unit = {
println(tc.text(a))
}
}
如果你真的希望你的隐式像对象一样被延迟评估,你可以使用具有显式类型的 implicit lazy val
。