Scala中的协变安全转换

问题描述 投票:0回答:1

我正在尝试为具有协变类型参数的类编写安全的类型转换:

case class Foo[+A](a: A) {
  def safeCast[B <: A](): Option[B] = ???
}

它是由动态外部数据源填充的,但是我至少要静态地确保BA的子类,如果类型转换失败,则返回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的东西来实现此目的的方法,将非常有用。

scala generics covariance
1个回答
0
投票

关于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
© www.soinside.com 2019 - 2024. All rights reserved.