假设我有一些类型类
trait FooBar[X]
和
FooBar[Int]
的实例:
given intIsFooBar: FooBar[Int] = new FooBar {}
现在,假设我有一个接口
Intf
有一些成员类型 A
并且还保证有一个 given FooBar[A]
:
trait Intf:
type A
given aIsFoobar: FooBar[A]
现在,我有类型
Int
,我有一个FooBar[Int]
,但是我如何为Int
实际实现这个接口?
如果我尝试
class IntImpl() extends Intf:
type A = Int
given aIsFoobar: FooBar[A] = summon
然后我得到“函数体IntImpl.aIsFoobar中的无限循环”错误,因为
summon
似乎看到aIsFoobar
而不是intIsFooBar
.
如果我尝试
summon
一些辅助辅助变量中的实例,就像这样:
class IntImpl() extends Intf:
type A = Int
private final val _aIsFoobar: FooBar[A] = summon
given aIsFoobar: FooBar[A] = _aIsFoobar
然后我遇到了初始化顺序问题:
aIsFoobar
原来是null
,我的应用程序崩溃了NullPointerExceptions
,这有点荒谬。
我也尝试过
export
,但是这些都不起作用:
export FooBar[Int] as aIsFoobar // doesn't compile, invalid syntax
我如何使“规范”
FooBar[Int]
作为aIsFoobar
给定成员可用?
完整代码:
trait FooBar[X]
given intIsFooBar: FooBar[Int] = new FooBar {}
trait Intf:
type A
given aIsFoobar: FooBar[A]
object IntImpl extends Intf:
type A = Int
given aIsFoobar: FooBar[A] = summon
在 Scala 2 中,您可以使用通过名称隐式隐藏的技巧
// Scala 2
trait FooBar[X] {
def value: String
}
object FooBar {
implicit val intIsFooBar: FooBar[Int] = new FooBar[Int] {
override val value: String = "a"
}
}
trait Intf {
type A
implicit def aIsFoobar: FooBar[A]
}
object IntImpl extends Intf {
type A = Int
override implicit val aIsFoobar: FooBar[A] = {
lazy val aIsFoobar = ???
implicitly[FooBar[A]]
}
}
println(IntImpl.aIsFoobar.value) // a
在 Scala 3 中,使用擦除类型的模式匹配的规范方法是什么?
在 Scala 3 中,这个技巧不起作用。
在 Scala 3 中,您可以尝试使方法 inline 并使用
scala.compiletime.summonInline
而不是 summon
// Scala 3
trait FooBar[X]:
def value: String
object FooBar:
given intIsFooBar: FooBar[Int] = new FooBar[Int]:
override val value: String = "a"
trait Intf:
type A
/*inline*/ given aIsFoobar: FooBar[A]
object IntImpl extends Intf:
type A = Int
override inline given aIsFoobar: FooBar[A] = summonInline[FooBar[A]]
println(IntImpl.aIsFoobar.value) // a
覆盖内联方法:https://docs.scala-lang.org/scala3/reference/metaprogramming/inline.html#rules-for-overriding
请注意,通过内联我们修改了方法语义。隐式在调用站点解析,而不是在定义站点
// Scala 2
trait FooBar[X] {
def value: String
}
object FooBar {
implicit val intIsFooBar: FooBar[Int] = new FooBar[Int] {
override val value: String = "a"
}
}
trait Intf {
type A
implicit def aIsFoobar: FooBar[A]
}
object IntImpl extends Intf {
type A = Int
override implicit val aIsFoobar: FooBar[A] = {
lazy val aIsFoobar = ???
implicitly[FooBar[A]]
}
}
{
implicit val anotherIntFooBar: FooBar[Int] = new FooBar[Int] {
override val value: String = "b"
}
println(IntImpl.aIsFoobar.value) // a
}
// Scala 3
trait FooBar[X]:
def value: String
object FooBar:
given intIsFooBar: FooBar[Int] = new FooBar[Int]:
override val value: String = "a"
trait Intf:
type A
/*inline*/ given aIsFoobar: FooBar[A]
object IntImpl extends Intf:
type A = Int
override inline given aIsFoobar: FooBar[A] = summonInline[FooBar[A]]
{
given anotherIntFooBar: FooBar[Int] = new FooBar[Int]:
override val value: String = "b"
println(IntImpl.aIsFoobar.value) // b
}
您可以询问如何在 Scala 3 中覆盖隐式而不更改定义站点语义。我不知道。
在 Scala 2 中,可以使用 Scala 2 宏实现内联。