从任意类型联合中删除一个类型



如果我在Scala 3中有一个任意类型的联合,是否可以写一个方法来"移除"一种来自联盟的类型?

类似于shapeless.ops.coproduct.Remove,但用于原生Scala 3。

例如,如果我有一个代表少量不同错误的联合类型,并且我想编写一个从特定错误类型恢复的函数,并将剩余的错误作为新的联合类型。

val result: Either[Foo | Bar | Baz | Bang, Thing]
val otherResult: Either[Foo | Bar, OtherThing]
// pretend syntax
def recoverBar[X, A](error: Bar | ...X)(f: Bar => A): Either[X, A] = 
error match {
case e: Bar => Right(f(e))
case otherError => Left(otherError)
}
// example usage
val recoveredResult: Either[Foo | Baz | Bang, Option[Thing]] = result
.map { Option.apply }
.left.flatMap { recoverBar(_)(_ => None) }
val recoveredOther: Either[Foo, OtherThing] = otherResult
.left.flatMap { recoverBar(_)(_ => OtherThing.default) }

。某种类型层次的通用办法

[Foo | Bar | Baz | Bang] =>> [Foo | Baz | Bang]
[Foo | Bar] =>> [Foo]
[Bar] =>> [Nothing]

您可以使用TypeTest:

class Remove[A]:
def apply[B](aOrB: A | B)(using tt: TypeTest[A | B, A]): Either[A, B] =
aOrB match
case a: A => Left(a)
case b    => Right(b.asInstanceOf[B])
def remove[A]: Remove[A] = Remove[A]
type Foo = Boolean | Int | String
val foo: Foo = "foo"
val noInt = remove[Int](foo)
// It inferred the correct type:
val inferred: Either[Int, Boolean | String] = noInt
// And we get the expected value: Right(foo)
println(noInt) 

这有点糟糕,匹配不能推断出另一个情况必须是B,但我认为这是我们目前能做的最好的。

最新更新