现在匹配类型 https://docs.scala-lang.org/scala3/reference/new-types/match-types.html价值水平有很多限制:
这种匹配表达式的特殊输入模式仅在以下情况下使用:
满足以下条件:
- 匹配表达式模式没有防护
- 匹配表达式受检者类型是匹配类型受检者类型的子类型
- 匹配表达式和匹配类型具有相同的事例数
- 匹配表达式模式都是类型化模式 https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#typed-patterns,这些类型是
=:=
到匹配类型中相应的类型模式
你的代码
type Z[A <: Tuple, B <: Tuple] <: Tuple = (A, B) match
case (EmptyTuple, EmptyTuple) => EmptyTuple
case (a *: as, b *: bs) => (a, b) *: Z[as, bs]
def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = (a, b) match
case (EmptyTuple, EmptyTuple) => EmptyTuple
case (ah *: at, bh *: bt) => (ah, bh) *: z(at, bt)
打破条件4。case (EmptyTuple, EmptyTuple)
and case (ah *: at, bh *: bt)
不是键入的模式。
尝试一下是有意义的
type Z[A <: Tuple, B <: Tuple] <: Tuple = (A, B) match
case (EmptyTuple, EmptyTuple) => EmptyTuple
case (a *: as, b *: bs) => (a, b) *: Z[as, bs]
def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = (a, b) match
case _: (EmptyTuple, EmptyTuple) => EmptyTuple
case t: (_ *: _, _ *: _) => t match
case (ah *: at, bh *: bt) => (ah, bh) *: z(at, bt)
但不幸的是,由于类型擦除,这不起作用
z((1, "a"), (true, 2.0)) // ()
实际上,case _: (EmptyTuple, EmptyTuple)
and case t: (_ *: _, _ *: _)
只是case _: (_, _)
并匹配一切。如果我们交换箱子z((1, "a"), (true, 2.0))
抛出运行时异常(java.lang.IndexOutOfBoundsException: 0
).
以下使用嵌套匹配类型/模式匹配的方法似乎有效
type Z[A <: Tuple, B <: Tuple] <: Tuple = A match
case EmptyTuple => Z1[B]
case a *: as => Z2[a, as, B]
type Z1[B <: Tuple] <: Tuple = B match
case EmptyTuple => EmptyTuple
type Z2[A, As <: Tuple, B <: Tuple] <: Tuple = B match
case b *: bs => (A, b) *: Z[As, bs]
def z[A <: Tuple, B <: Tuple](a: A, b: B): Z[A, B] = a match
case _: EmptyTuple => z1(b)
case a1: (_ *: _) => a1 match
case a2 *: as => z2(a2, as, b)
def z1[B <: Tuple](b: B): Z1[B] = b match
case _: EmptyTuple => EmptyTuple
def z2[A, As <: Tuple, B <: Tuple](a: A, as: As, b: B): Z2[A, As, B] = b match
case b1: (_ *: _) => b1 match
case b2 *: bs => (a, b2) *: z(as, bs)
// compiles
summon[Z[(Int, String), (Boolean, Double)] =:= ((Int, Boolean), (String, Double))]
z((1, "a"), (true, 2.0)) // ((1,true),(a,2.0))
// doesn't compile
// summon[Z[(Int, String, Long), (Boolean, Double)] =:= ((Int, Boolean), (String, Double))]
// z((1, "a", 3L), (true, 2.0))
// Match type reduction failed since selector EmptyTuple.type
// matches none of the cases
// case b *: bs => (Long, b) *: Z[EmptyTuple.type, bs]
// doesn't compile
// summon[Z[(Int, String), (Boolean, Double, Long)] =:= ((Int, Boolean), (String, Double))]
// z((1, "a"), (true, 2.0, 3L))
// Match type reduction failed since selector Long *: EmptyTuple.type
// matches none of the cases
// case EmptyTuple => EmptyTuple
如何让匹配类型在 Scala 3 中正常工作 https://stackoverflow.com/questions/64434175/how-to-get-match-type-to-work-correctly-in-scala-3
Shapeless3 和注释 https://stackoverflow.com/questions/74355212/shapeless3-and-annotations