在一个文件中,我有:
trait JsonSchema[T] {
val propertyType: String
override def toString: String = propertyType
}
object JsonSchema {
implicit def stringSchema: JsonSchema[String] = new JsonSchema[String] {
override val propertyType: String = "string"
}
implicit def intSchema: JsonSchema[Int] = new JsonSchema[Int] {
override val propertyType: String = "integer"
}
implicit def booleanSchema: JsonSchema[Boolean] = new JsonSchema[Boolean] {
override val propertyType: String = "boolean"
}
}
在我的主文件中:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])
object JsonSchemaExample extends App {
println(MetaHolder(3).meta.toString)
println(MetaHolder("wow").meta.toString)
}
这很笨拙。现在假设我这样做:
case class MetaHolder[T](v: T) {
val meta: JsonSchema[T] = implicitly[JsonSchema[T]]
}
它不再编译。为什么?
我的目标是通过为所有内容添加val meta
来修改 scala Finch 库中的匿名Endpoint
类。到目前为止,我已经能够在没有任何花哨业务的情况下做到这一点,但现在我想用无形状做一些花哨的隐式解决方案,为任意案例类提供一个JsonSchema
定义。我的问题是如何在保持向后兼容性的同时做到这一点。如:为想要选择加入的人提供 jsonschema 元功能,不要改变任何不想使用 meta 的人的编译负担,
如果我走第一条路线,添加隐式参数,那不是需要每个人添加特殊导入吗?还是我错过了什么,是否仍会保持向后兼容性?
参数之间的implicit x: X
和体内implicitly[X]
有很大的区别。
当您说implicitly[X]
时,这意味着"立即检查当前范围内是否存在隐式X
"。
当您说def foo(...)(implicit x: X) = ...
时,这意味着"稍后在调用foo
时检查在调用站点的范围内会有一个隐式X
(现在在内部foo
只是假设而不检查是否存在("。
class Foo(...)(implicit x: X)
类似于后者,"检查何时调用构造函数时是否会有隐式X
"。
关于用户是否必须导入。如果将类型X
的隐式放入X
的伴随对象,则会自动找到它们(类型X[Y]
的隐式应放入X
或Y
的伴随对象(。如果将它们放在其他地方,则必须将它们导入到当前范围。
为了使implicitly[JsonSchema[T]]
进行编译,隐式作用域中必须有一个JsonSchema[T]
,这意味着必须有一个JsonSchema[T]
(或可隐式转换为JsonSchema[T]
的东西(作为隐式参数传递,就像你所做的那样:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])