wla*_*031 6 generics scala pattern-matching scala-3
我试图将我的思想从 Java 背景(和一点 Scala 2)迁移到 Scala 3,并实现一种版本,PartialFunction.orElse但使用联合类型作为输入参数而不是交叉类型:
trait F[A, B] extends (A => B) {
def orElse[A1, B1](other: F[A1, B1]): F[A | A1, B | B1] = {
val self = this
new F[A | A1, B | B1] {
override def apply(v: A | A1): B | B1 = {
helper(v)
}
transparent inline def helper(v: A | A1): Any = {
inline v match {
case _: A => self.apply(v.asInstanceOf[A])
case _: A1 => other.apply(v.asInstanceOf[A1])
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我最终发现两个调用都转到“匹配”的第一个分支:
val f1 = new F[Int, String] {
override def apply(v: Int): String = s"Int => String : $v"
}
val f2 = new F[String, Int] {
override def apply(v: String): Int = v.length
}
val f = f1.orElse(f2)
println(f(42)) // prints "Int => String : 42"
println(f("hello")) // fails in runtime because of trying casting String to Int
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是,它甚至可能吗?如果是,我错过了什么?
助手可能是内联的,但整个特征不是内联的,而且 也不是orElse,所以A和A1仍然被删除。您应该已经从编译器收到警告,指出A并且A1无法在运行时检查。为此,您需要在范围内有 aTypeable[A]和 a (并且 a也应该有效,因为它们更具体,但无论出于何种原因,编译器都不会使用它们)。Typeable[A1]TypeTest[A | A1, A]TypeTest[A | A1, A1]
我决定使用扩展方法而不是特征,因为这样更简单。这样,您也可以将它用于普通函数,只要它们Typeable在范围内有一个实例(我相信Int、String和其他没有类型参数或成员的原语/类的实例是自动合成的)。(斯卡斯蒂)
import scala.reflect.Typeable
extension [A1: Typeable, B1](f1: A1 => B1)
def orElse[A2: Typeable, B2](f2: A2 => B2): (A1 | A2) => (B1 | B2) =
case v1: A1 => f1(v1)
case v2: A2 => f2(v2)
val f1 = (v: Int) => s"Int => String : $v"
val f2 = (v: String) => v.length
val f = f1.orElse(f2)
Run Code Online (Sandbox Code Playgroud)
然而,显式检查类型对我来说感觉像是一种反模式,因此如果您能够提供有关更大问题的更多详细信息,将会有所帮助。