use*_*ser 5 scala tuples dotty scala-3
由于我无法控制的原因,我的方法以元组的形式接收输入。这个元组应该只包含 的实例Foo,即它应该看起来像(Foo, Foo ... Foo)并且不应该有String或Int在里面。我想在编译时检查这个而不是在运行时抛出异常。我怎样才能做到这一点?
以下是我目前拥有的代码,这是不对的:
def f(tupleOfFoos: Tuple): Tuple = {
for (x <- tupleOfFoos) assert(x.isInstanceOf[Foo])
mapTuple(tupleOfFoos, irrelevantFunction)
}
Run Code Online (Sandbox Code Playgroud)
我愿意使用 Shapeless 或 Dotty/Scala 3 中引入的新功能。
在 Scala 2 中,使用 Shapeless,您可以执行此操作 ( Scastie ):
def f[T <: Product, H <: HList](tupleOfFoos: T)(
implicit gen: Generic.Aux[T, H],
hev: LiftAll[({type E[T] = Foo =:= T})#E, H]
) = tupleOfFoos
Run Code Online (Sandbox Code Playgroud)
LiftAll确保Foo =:= X每个Xin都有一个实例H,并gen确保T和H不是完全不相关的类型。
在 Dotty 中,您可以为此添加一个具有匹配类型的证据参数:
type Homogenous[H, T <: Tuple] = T match {
case EmptyTuple => DummyImplicit
case H *: t => Homogenous[H, t]
case _ => Nothing
}
def f[T <: Tuple](tupleOfFoos: T)(using Homogenous[Foo, T]) = tupleOfFoos
Run Code Online (Sandbox Code Playgroud)
这将允许您调用f((Foo(), Foo(), Foo()))但不能调用f((1, 2, 3))。
Homogenous是一个递归匹配类型,基本情况为EmptyTuple。如果元组是空的,那么它不会被 non- Foos填充,所以类型变成DummyImplicit,它已经在范围内隐含了。否则,我们检查它是否看起来像(H, ...)/ H *: t,在这种情况下,我们需要检查元组 ( t)的其余部分是否也有效。如果它与第二种情况不匹配,我们就知道该元组无效,在这种情况下,结果是Nothing,理智的人不会对其进行隐含的值。
如果你想使用上下文边界,你可以创建一个额外的柯里化类型(Scastie):
type Homo2[H] = [T <: Tuple] =>> Homogenous[H, T]
def f[T <: Tuple : Homo2[Foo]](tupleOfFoos: T) = tupleOfFoos
Run Code Online (Sandbox Code Playgroud)
不幸的是,我无法让它与单一咖喱类型(Scastie)一起使用:
type Homogenous[H] = [T <: Tuple] =>> T match {
case EmptyTuple => DummyImplicit
case H *: t => Homogenous[H][t]
case _ => Nothing
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
120 次 |
| 最近记录: |