win*_*son 3 reflection scala scala-3
TypeTest我在理解scala3 中的 s 如何替代scala 2 中的 s 时遇到问题。TypeTag用例能够匹配像 x: List[Int] 这样的通用参数。
我试图解决的具体例子:
enum Foo :
case Bar()
case Baz()
case class Mod[T <: Foo](modFn: T => T)
def modifyBarsOrBaz(mod: Mod[_]) = mod match
case barMod: Mod[Foo.Bar] => ???
case bazMod: Mod[Foo.Baz] => ???
Run Code Online (Sandbox Code Playgroud)
编译器警告中的编译结果(如预期)
the type test for Mod[Foo.Bar] cannot be checked at runtime以及一个无法触及的案例。
现在我的问题是:这在 scala3 中可以做到吗?
我的印象是,我必须以某种方式TypeTest[Any, Mod[Foo.X]]为所有作为枚举子类的 X 提供一个Foo。
但我什至很难实现这些测试,以及了解什么using参数modifyBarsOrBaz其工作所需的
因此我想出了以下(不起作用)解决方案:
def modifyBarsOrBaz[T <: Foo](mod: Mod[T])(using TypeTest[Any, Mod[T]]) = mod match
case barMod: Mod[Foo.Bar] => ???
case bazMod: Mod[Foo.Baz] => ???
Run Code Online (Sandbox Code Playgroud)
以及一个简单的 tt 实现
val tt: TypeTest[Any, Mod[Foo.Bar]] =
new TypeTest[Any, Mod[Foo.Bar]] :
def unapply(x: Any): Option[x.type & Mod[Foo.Bar]] = x match
case m: Mod[_] => ??? // what to do here? use a classtag on Mod?
Run Code Online (Sandbox Code Playgroud)
我尝试在网上搜索答案,但由于这是相当新的,所以我并不幸运。有什么提示吗?
这里的问题是 aTypeTest[Any, Mod[T]]将能够检查 an 是否Any是 a Mod[T],而不是检查 a 是否Mod[T]是 aMod[Foo.Bar]或 a Mod[Foo.Baz]。您需要的是TypeTest[Any, Mod[Foo.Bar]和TypeTest[Any, Mod[Foo.Baz]:
def modifyBarsOrBaz(mod: Mod[?])(using asBar: TypeTest[Any, Mod[Foo.Bar]], asBaz: TypeTest[Any, Mod[Foo.Baz]]) =
mod match
case asBar(barMod) => println("barMod")
case asBaz(bazMod) => println("bazMod")
Run Code Online (Sandbox Code Playgroud)
我不知道为什么 simplebarMod: Mod[Foo.Bar]不能与TypeTest[Any, Mod[Foo.Bar]]in 范围一起使用,我稍后会讨论这个问题。
但是,您现在必须TypeTest自己实际实现这些。由于 JVM 没有具体化,因此您必须T在Mod类中存储相关信息。如果你真的想保留Mod一个案例类,你可以这样做:
type BarOrBaz[T <: Foo] <: String = T match {
case Foo.Bar => "Bar"
case Foo.Baz => "Baz"
}
case class Mod[T <: Foo](modFn: T => T, tag: BarOrBaz[T])
Run Code Online (Sandbox Code Playgroud)
TypeTest现在可以通过内联方法提供 和Bar的实例:Baz
import compiletime.constValue
inline given [T <: Foo]: TypeTest[Mod[?], Mod[T]] = new TypeTest:
def unapply(mod: Mod[?]) = Option.when(mod.tag == constValue[BarOrBaz[T]])(mod.asInstanceOf[mod.type & Mod[T]])
Run Code Online (Sandbox Code Playgroud)
modifyBarsOrBaz将会
def modifyBarsOrBaz(mod: Mod[?])(using asBar: TypeTest[Mod[Foo], Mod[Foo.Bar]], asBaz: TypeTest[Mod[Foo], Mod[Foo.Baz]]) = mod match
case asBar(barMod) => println("barMod")
case asBaz(bazMod) => println("bazMod")
Run Code Online (Sandbox Code Playgroud)
为了方便起见,apply可以创建一个内联方法:
object Mod:
inline def apply[T <: Foo](modFn: T => T) = new Mod(modFn, constValue[BarOrBaz[T]])
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用它(Scastie):
modifyBarsOrBaz(Mod[Foo.Bar](bar => bar)) //barMod
modifyBarsOrBaz(Mod[Foo.Baz](baz => baz)) //bazMod
Run Code Online (Sandbox Code Playgroud)
但实际上,对这样的类型测试的需求对我来说就像是一种代码味道。我建议重新考虑你的设计来解决这个问题,而不是使用这样的标签。
| 归档时间: |
|
| 查看次数: |
758 次 |
| 最近记录: |