scala - 与 Scala 隐式类型不匹配
问题描述
我正在尝试在 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
的调用,它需要 a ,这是我给它的。我没有在任何地方定义过需要.toHTML
HTMLEnrichment
HTMLSerializer
toHTML
Int
解决方案
这是因为您不小心重载了该toHTML
方法。您收到的错误是因为String.apply
返回给定索引处的字符,这就是您收到有关Int
.
Intelij 在识别这种阴影方面并不总是有效的。将隐式机制远离域模型是一个好主意,例如将专门的序列化解耦为隐式,就像你正在做的那样:
implicit object UserSerializer extends HTMLSerializer[User] {
def serialize(user: User): String = s"<div>${user.name} (${user.age} yo) <a href=${user.email}/> </div>"
}
然后从您的 中删除所有内容user
,并可能添加一个助手。
trait HTMLSerializer {
def toHTML: String
}
object HTMLSerializer {
// if you put this here you don't need to explicitly import it.
implicit class HTMLEnrichment[T](val value: T) extends AnyVal {
def toHTML(implicit serializer: HTMLSerializer[T]): String =
serializer.serialize(value)
}
}
这意味着您可以简单地获得与使用伴随方法相同的效果,但您可以保持一切都很好地解耦,并且您不会冒着产生这些阴影效果的风险。
推荐阅读
- android - Android TextView 在缩放时显得模糊
- android - android如何在运行时将ccp程序与设备库动态链接
- angular - 角度推送不是推送而是替换列表中的数据
- tensorflow - TensorFlow,将两个检查点值合二为一并恢复
- python - 我遇到了 mod_wsgi + Django + Apache 的问题
- rest - 如何让响应时间放心?
- ubuntu - 服务器上的 jupyter 笔记本“内核正在启动,请等待”
- php - PhpStorm - 检查 NULL 值
- bash - 正确执行具有交互式输入的 bash 命令
- xml - 与“manifest”元素类型关联的“android:versionCode”属性的“android”前缀未链接