如何解决带有标记类型和播放 Json 格式类型类派生的编译错误
在下面的示例中,我想对我的类的 id 使用标记类型。我创建了一个实用程序特性来减少一些样板(标签/读取/写入声明):
import java.util.UUID
import play.api.libs.json.{Format,Json,Reads,Writes}
trait Opaque[A] {
protected type Tagged[U] = { type Tag = U }
type @@[U,T] = U with Tagged[T]
trait Tag
def tag(a: A): A @@ Tag = a.asInstanceOf[A @@ Tag]
def untag(a: A @@ Tag): A = a
implicit def reads(implicit r: Reads[A]): Reads[A @@ Tag] =
r.map(tag)
implicit def writes(implicit w: Writes[A]): Writes[A @@ Tag] =
w.contramap(untag)
implicit def format(implicit r: Reads[A],w: Writes[A]): Format[A @@ Tag] =
Format(reads(r),writes(w))
}
final case class Foo(id: Foo.FooId.T,f1: Boolean)
object Foo {
object FooId extends Opaque[UUID] {
type T = UUID @@ Tag
}
import FooId._
implicit val fmt: Format[Foo] = Json.format[Foo]
}
final case class Bar(id: Bar.BarId.T,fooId: Foo.FooId.T,b1: String)
object Bar {
object BarId extends Opaque[UUID] {
type T = UUID @@ Tag
}
import Foo.FooId._
import BarId._
implicit val format: Format[Bar] = Json.format[Bar]
}
编译器出现以下错误:
implicit val format: Format[Bar] = Json.format[Bar]
^
<pastie>:43: error: No instance of play.api.libs.json.Format is available for Opaque.<refinement>,Opaque.<refinement> in the implicit scope (Hint: if declared in the same file,make sure it's declared before)
我无法解释为什么我有这种行为,错误消息不明确。我正在导入导出 Format
类格式所需的 FooId
和 BarId
的 Bar
。
解决方法
问题是隐式的名字很重要。
非常简单的例子如下:
object MyObject {
implicit val i: Int = ???
}
import MyObject._
implicit val i: String = ???
// implicitly[Int] // doesn't compile
// implicitly[String] // doesn't compile
但是
object MyObject {
implicit val i: Int = ???
}
import MyObject._
implicit val i1: String = ???
implicitly[Int] // compiles
implicitly[String] // compiles
如果您希望派生 Json.format[Bar]
起作用,则范围内应该有隐式 Format[Bar.BarId.T]
、Format[Foo.FooId.T]
,即 Format
字段的 Bar
实例。如果你做唯一的导入
import Foo.FooId._
implicitly[Format[Foo.FooId.T]] // compiles
和
import BarId._
implicitly[Format[Bar.BarId.T]] // compiles
但是如果你同时导入两者,因为隐式的名称会发生冲突
import Foo.FooId._
import BarId._
// implicitly[Format[Foo.FooId.T]] // doesn't compiles
// implicitly[Format[Bar.BarId.T]] // doesn't compiles
例如,您可以将 trait Tag
移到 trait Opaque
之外并进行唯一的导入。那么
implicitly[Format[Foo.FooId.T]]
implicitly[Format[Bar.BarId.T]]
Json.format[Bar]
会编译。
https://youtu.be/1h8xNBykZqM?t=681 我们在设计隐式时犯的一些错误,错误 #1
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。