我正在尝试在 Scala 3 中开发一个从类型
Error | A
到类型 Either[Error, A]
的隐式转换器。转换器的代码如下:
object MyConversions:
given unionTypeToEither[Error, A]: Conversion[Error | A, Either[Error, A]] with
def apply(value: Error | A): Either[Error, A] = value match
case error: Error => Left(error)
case a: A => Right(a)
转换器应使用以下代码:
import in.rcard.raise4s.MyConversions.unionTypeToEither
val actual: String | Int = 42
val actualEither: Either[String, Int] = actual
编译器给了我以下错误:
[error] 90 | val actualEither: Either[String, Int] = actual
[error] | ^^^^^^
[error] | Found: (actual : String | Int)
[error] | Required: Either[String, Int]
[error] |
[error] | longer explanation available when compiling with `-explain`
[error] one error found
有人可以帮助我吗?
问题来自于
Either[A, B]
和 A | B
之间的语义差异。
A | B
与 B | A
相同,任何 A
与 A | Nothing
相同 - 虽然组合 2 种类型(与 |
)始终是明确的,但分解始终是不明确的。如果没有例如,你就无法做到这一点使用自定义逻辑和附加假设编写一些宏。
根据我的经验,如果你尝试使用推理,例如通过将其传递给类似以下内容来分割
A | B
:
[X, Y](value: X | Y): Either[X, Y] = ...
你实际上得到的是
Either[A | B, Nothing]
或者一些有点无用的东西。
作为对您的类型有一定了解的人,您可能会假设:
A
和 B
的最低上限为 Any
/AnyRef
/AnyVal
A <:< B
也没有 B <:< A
关系但作为一个非常普遍的规则,如果所有代码都知道类型是
<: Any
,那么编译器就没有什么可处理的,并且可能没有人尝试处理类型推断以使其以某种智能方式工作.
假设您有某种确定性的方法来决定哪个组件最先出现,哪个组件最后出现(即:
A | B
中左边的内容和右边的内容,因为它与B | A
相同),您会仍然需要自己编写分解逻辑,可能是通过编写宏并接受某些情况无法通过它来处理。