scala - 通过类型参数对 ADT 列表进行类型安全过滤
问题描述
考虑以下示例:
一世。
class A
class B
sealed trait Test {
type Meta
}
case class Test1() extends Test {
type Meta = A
}
case class Test2() extends Test {
type Meta = B
}
case class Info[T <: Test](t: T, m: T#Meta)
//Filters List[Info[_ <: Test]] by a generic type T <: Test and returns List[Info[T]]
def filter[T <: Test: ClassTag](lst: List[Info[_ <: Test]])(
implicit ev: ClassTag[T#Meta]): List[Info[T]] =
lst.collect {
case Info(t: T, a: T#Meta) =>
val i: Info[T] = Info[T](t, a)
i
}
让我卡住的事情是PartialFunction
'scase
是否详尽无遗。我尝试完全模式匹配Info[_ <: Test]
如下:
二、
val t: Info[_ <: Test] = ???
t match {
case Info(t: Test1, a: Test1#Meta) =>
println("1")
case Info(t: Test2, a: Test2#Meta) =>
println("2")
}
并收到以下(非常可怕的)警告:
match may not be exhaustive.
It would fail on the following inputs:
Info((x: _$2 forSome x not in (Test1, Test2)), (x: _$2#Meta forSome x not in (A, B))),
Info((x: _$2 forSome x not in (Test1, Test2)), ??), Info((x: _$2 forSome x not in (Test1, Test2)), A()),
Info((x: _$2 forSome x not in (Test1, Test2)), B()), Info(??, (x: _$2#Meta forSome x not in (A, B))),
Info(Test1(), (x: _$2#Meta forSome x not in (A, B))),
Info(Test1(), B()), Info(Test2(), (x: _$2#Meta forSome x not in (A, B))),
Info(Test2(), A())
问题:我在语义方面是否正确或遗漏了一些奇怪的 sfilter
的情况下的实现?case
解决方案
好吧,如您所见,您有一个建议的破坏案例列表。例如,Info(Test1(), B())
。让我们构建其中之一。
与 中的路径相关类型不同def foo(t: Test)(meta: t.Meta) = ???
,使用它们时的类型投影case class Info
不会编码T = Test1 => T#Meta = A
. 虽然我需要一个简单的实用方法来说服 scalac 推断出我想要的类型。
def castMeta[T <: Test](t: T#Meta): Test#Meta = t
有了它,我们可以从 A 和 B 中获取类型为 Test#Meta 的值。
所以,
val t: Info[_ <: Test] = Info[Test](Test1(), castMeta[Test2](new B))
将在运行时导致 a MatchError
,并使其不涉及任何“黑客”,如 null、asInstanceOf
s 或ClassTag
s。
还要注意,Type#Member
由于健全性问题,形式的一般类型投影计划在 Scala 3 中删除。
编辑:请注意,您的过滤器可能会执行您想要的操作,因为您自己提供了目标类型对,只是您的模型完全允许 scalac 警告您的奇怪情况:)
推荐阅读
- pip - python和pip在anaconda环境中不匹配
- python - pysftp 库在 AWS lambda 层中不起作用
- debugging - 是否有推荐的端到端自动化测试调试策略?
- python - 如何提取唯一的首字母
- c# - 我正在尝试通过我的网络应用程序向用户发送电子邮件。但是gmail阻止了电子邮件发送。请问有什么解决办法吗?
- javascript - 节点 js 在相同的 url 上分隔应用程序,除以特定路径
- asp.net - 在 IIS 网络服务器中更新 web.config 的步骤是什么
- java - Spring禁用Swagger-ui进行生产
- javascript - 如何让 Materialise Feature Discovery Block 显示在我的网页上?
- android - JSON 解析错误:使用 ReactNative 的意外标识符“成功”