元组的 Scala 3 类型绑定 `<:<` 技巧
Scala 3 type bound `<:<` trick for tuples
Adam Warski 在在线课程中展示了一个证明元组具有特定结构的技巧:
第一个实现是
def sequence[T <: Tuple](t: T): Option[InverseMap[T, Option]] =
val unwrapped = t.productIterator.collect { case Some(v) => v}.toArray[Any]
if unwrapped.length == t.productArity then Some(Tuple.fromArray(unwrapped).asInstanceOf[InverseMap[T, Option]])
else None
允许(但不应该)
sequence(("x", true)) // compiles
并用技巧实现
def betterSequence[T <: Tuple](t: T)(using T <:< Map[InverseMap[T, Option], Option]): Option[InverseMap[T, Option]] =
val unwrapped = t.productIterator.collect { case Some(v) => v}.toArray[Any]
if unwrapped.length == t.productArity then Some(Tuple.fromArray(unwrapped).asInstanceOf[InverseMap[T, Option]])
else None
betterSequence(("x", true)) // compile error
有人能解释一下吗
(using T <:< Map[InverseMap[T, Option], Option])
有效,为什么 T
是 Map
的子类型?
InverseMap[T, Foo]
接受一个看起来像 (Foo[t1], Foo[t2], ..., Foo[tn])
的元组 T
并将其转换为元组 (t1, t2, ..., tn)
。如果 T
没有那个结构,即它不是一堆 Foo
,它就不会编译(有一些神秘的错误)。这是证明元组中只有 Option
s 的主要内容。
接下来的问题是如何将这个类型插入到betterSequence
方法中。 Map[T, Foo]
将看起来像 (t1, t2, ..., tn)
的元组 T
变成 (Foo[t1], Foo[t2], ..., Foo[tn])
(InverseMap
的倒数)。因此,Map[InverseMap[T, Option], Option]
只是 T
(想想数学,其中 f(f^-1(x)) 又是 x。边界 T <:< T
将始终为真,但前提是InverseMap
先成功。
Adam Warski 在在线课程中展示了一个证明元组具有特定结构的技巧:
第一个实现是
def sequence[T <: Tuple](t: T): Option[InverseMap[T, Option]] =
val unwrapped = t.productIterator.collect { case Some(v) => v}.toArray[Any]
if unwrapped.length == t.productArity then Some(Tuple.fromArray(unwrapped).asInstanceOf[InverseMap[T, Option]])
else None
允许(但不应该)
sequence(("x", true)) // compiles
并用技巧实现
def betterSequence[T <: Tuple](t: T)(using T <:< Map[InverseMap[T, Option], Option]): Option[InverseMap[T, Option]] =
val unwrapped = t.productIterator.collect { case Some(v) => v}.toArray[Any]
if unwrapped.length == t.productArity then Some(Tuple.fromArray(unwrapped).asInstanceOf[InverseMap[T, Option]])
else None
betterSequence(("x", true)) // compile error
有人能解释一下吗
(using T <:< Map[InverseMap[T, Option], Option])
有效,为什么 T
是 Map
的子类型?
InverseMap[T, Foo]
接受一个看起来像 (Foo[t1], Foo[t2], ..., Foo[tn])
的元组 T
并将其转换为元组 (t1, t2, ..., tn)
。如果 T
没有那个结构,即它不是一堆 Foo
,它就不会编译(有一些神秘的错误)。这是证明元组中只有 Option
s 的主要内容。
接下来的问题是如何将这个类型插入到betterSequence
方法中。 Map[T, Foo]
将看起来像 (t1, t2, ..., tn)
的元组 T
变成 (Foo[t1], Foo[t2], ..., Foo[tn])
(InverseMap
的倒数)。因此,Map[InverseMap[T, Option], Option]
只是 T
(想想数学,其中 f(f^-1(x)) 又是 x。边界 T <:< T
将始终为真,但前提是InverseMap
先成功。