【发布时间】:2019-04-22 06:05:26
【问题描述】:
我正在尝试在 Scala 中使用隐式。
object TypeClasses extends App {
trait HTMLWritable {
def toHTML: String
}
case class User(name: String, age: Int, email: String) extends HTMLWritable {
override def toHTML: String = s"<div>$name ($age yo) <a href=$email/> </div>"
}
val john = User("John", 32, "john@rockthejvm.com")
trait HTMLSerializer[T] {
def serialize(value: T): String
}
object UserSerializer extends HTMLSerializer[User] {
def serialize(user: User): String = s"<div>${user.name} (${user.age} yo) <a href=${user.email}/> </div>"
}
implicit class HTMLEnrichment[T](value: T) {
def toHTML(serializer: HTMLSerializer[T]): String = serializer.serialize(value)
}
println(john.toHTML(UserSerializer))
}
此代码无法编译:
Error:(41, 23) type mismatch;
found : lectures.part4implicits.TypeClasses.UserSerializer.type
required: Int
println(john.toHTML(UserSerializer))
我无法理解该消息,因为根据 IntelliJ,john.toHTML 是对 HTMLEnrichment 类上的 toHTML 方法的调用,它需要 HTMLSerializer,这是我给它的.我没有在任何地方定义需要Int 的toHTML 方法。
【问题讨论】:
-
问题是因为你的
User已经有一个toHTML方法,它将使用它,而不是扩展方法。而且,由于该方法不带参数,编译器将其解释为在返回toHTML时调用apply方法,这是一个String,其apply方法按索引返回Character。这就是为什么编译器会警告Int- 尝试使用另一个名称(例如toHTML2) 或删除正常的toHTML,或创建另一个User类,等等。 -
顺便说一句,通常将 隐式类 与 value class 结合使用以避免实例化。此外,通常
serializer是隐式参数,UserSerializer也是隐式参数。因为人们通常不想明确地传递它。 - 此外,案例类应该是最终的。而且,一般来说,对于像这样的简单用例,最好使用 implicit vals (with explicit type signature) 而不是对象。implicit val UserSerializer: HTMLSerializer[User] = new HTMLSerializer[User] { ... }.