我正在尝试为具有协变类型参数的类编写安全的类型转换:
case class Foo[+A](a: A) {
def safeCast[B <: A](): Option[B] = ???
}
它是由动态外部数据源填充的,但是我至少要静态地确保B
是A
的子类,如果类型转换失败,则返回None
。我不断收到关于A
处于协变位置的错误。我可以通过省略<: A
来进行类型检查,但是如何指定有关B
的静态保证?
[我知道这是在防止将Foo[Dog]
分配给Foo[Animal]
val,然后尝试执行类似safeCast[Mammal]
的情况,其中Mammal
不是Dog
的子类型。就我而言,这确实可以。甚至允许强制转换为Animal
的超类型。我主要是想静态地阻止某人尝试safeCast[Plant]
。
注意,我可以使用如下所示的类外部函数对它进行类型检查,但是我想在类上使用方法。
def safeCast[A, B <: A](foo: Foo[A]): Option[B] = ???
作为奖励,如果您知道一种使用cat或没有isInstanceOf
的东西来实现此目的的方法,将非常有用。
关于typeclass方法。
import scala.reflect.ClassTag
final case class Foo[+A](a: A)
@annotation.implicitNotFound("${B} is not a subtype of ${A}")
sealed trait Caster[A, B] {
def safeCast(a: A): Option[B]
}
object Caster {
implicit def subtypeCaster[A, B](implicit ev: B <:< A, ct: ClassTag[B]): Caster[A, B] =
new Caster[A, B] {
override def safeCast(a: A): Option[B] =
ct.unapply(a)
}
}
object syntax {
object caster {
implicit class CasterOps[A](private val a: A) extends AnyVal {
@inline
final def safeCast[B](implicit caster: Caster[A, B]): Option[B] =
caster.safeCast(a)
}
}
}
可以像这样被起诉:
sealed trait Animal
final case class Dog(name: String) extends Animal
final case class Cat(name: String) extends Animal
import syntax.caster._
val animal: Animal = new Dog("luis")
animal.safeCast[Dog]
// res: Option[Dog] = Some(Dog("luis"))
animal.safeCast[Cat]
// res: Option[Cat] = None
animal.safeCast[String]
// compile error: String is not a subtype of Animal