使用类型参数进行隐式解析时,为什么 val 放置很重要?
When doing implicit resolution with type parameters, why does val placement matter?
在一个文件中,我有:
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
类。到目前为止,我已经能够在没有任何花哨业务的情况下做到这一点,但现在我想用 shapeless 做一些花哨的隐式解析,为任意情况 类 提供 JsonSchema
定义。我的问题是如何在保持向后兼容性的同时做到这一点。如:为想要选择加入的人提供 jsonschema 元特性,不要为不想使用元的人改变编译负担,
如果我改用第一条路线,添加一个隐式参数,是否需要每个人都添加一个特殊的导入?还是我遗漏了一些东西,是否仍会保持向后兼容性?
为了让 implicitly[JsonSchema[T]]
编译,隐式作用域中必须有一个 JsonSchema[T]
,这意味着必须有一个 JsonSchema[T]
(或者可以隐式转换为 JsonSchema[T]
) 作为隐式参数传递,就像您使用的那样:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])
参数之间的implicit x: X
和body内部的implicitly[X]
差别很大
当您说 implicitly[X]
时,这意味着 "check now whether in the current scope there is an implicit X
"。
当您说 def foo(...)(implicit x: X) = ...
时,这意味着 "check later when foo
is called that in the scope of the call site there will be an implicit X
(and for now inside foo
just assume without checking that there is)"。
class Foo(...)(implicit x: X)
类似于后者,"check when constructor is called that there will be an implicit X
".
关于用户是否必须导入。如果您将类型 X
的隐式放入 X
的伴随对象,那么它们将被自动找到(类型 X[Y]
的隐式应该放入 X
或 Y
).如果将它们放在其他地方,则必须将它们导入当前范围。
在一个文件中,我有:
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
类。到目前为止,我已经能够在没有任何花哨业务的情况下做到这一点,但现在我想用 shapeless 做一些花哨的隐式解析,为任意情况 类 提供 JsonSchema
定义。我的问题是如何在保持向后兼容性的同时做到这一点。如:为想要选择加入的人提供 jsonschema 元特性,不要为不想使用元的人改变编译负担,
如果我改用第一条路线,添加一个隐式参数,是否需要每个人都添加一个特殊的导入?还是我遗漏了一些东西,是否仍会保持向后兼容性?
为了让 implicitly[JsonSchema[T]]
编译,隐式作用域中必须有一个 JsonSchema[T]
,这意味着必须有一个 JsonSchema[T]
(或者可以隐式转换为 JsonSchema[T]
) 作为隐式参数传递,就像您使用的那样:
case class MetaHolder[T](v: T)(implicit val meta: JsonSchema[T])
参数之间的implicit x: X
和body内部的implicitly[X]
差别很大
当您说 implicitly[X]
时,这意味着 "check now whether in the current scope there is an implicit X
"。
当您说 def foo(...)(implicit x: X) = ...
时,这意味着 "check later when foo
is called that in the scope of the call site there will be an implicit X
(and for now inside foo
just assume without checking that there is)"。
class Foo(...)(implicit x: X)
类似于后者,"check when constructor is called that there will be an implicit X
".
关于用户是否必须导入。如果您将类型 X
的隐式放入 X
的伴随对象,那么它们将被自动找到(类型 X[Y]
的隐式应该放入 X
或 Y
).如果将它们放在其他地方,则必须将它们导入当前范围。