繁体   English   中英

如何覆盖特定类型的 Scala 泛型方法?

[英]How to override Scala generic methods for specific types?

我目前有这样的事情:

case class Bear(a: String, b: String) {
   val can: Can[T] = ?? 
   def drink[T](str: String) = can.open(str)
}

我需要将其修改为仅用于 4 种类型 A、B、C 和 D。例如,给定一个 Bear 实例,我们应该只能调用bearinstance.drink[A]("abc")bearinstance.drink[B]("abc")bearinstance.drink[C]("abc")bearinstance.drink[D]("abc") 不应允许任何其他类型。

现在的问题是如何为特定类型重写此方法?

另一个问题是can ,假设我设法将drink重写为仅用于类型“A”、“B”、“C”和“D”,我将必须为所有四种类型创建can作为成员变量。 如何根据类型动态创建通用方法 select can 一种选择是在 class 之外隐式声明can ,但它需要声明 class 参数。

任何线索将不胜感激。

您需要这样做的事实意味着您确实应该重构您的代码。

但无论如何...

尝试使用隐式参数:

case class Bear(a: String, b: String) {
   val can: Can[T] = ???
   def drink[T](str: String)(implicit ev: CanDrink[T]) = can.open(str)
}

然后使用隐式实例创建一个特征CanDrink

trait CanDrink[T]
implicit object ACanDrink extends CanDrink[A]
implicit object BCanDrink extends CanDrink[B]
//And so on

现在你可以这样称呼它:

bearinstance.drink[A]("abc") 
//Gets implicit object ACanDrink

bearinstance.drink[X]("abc") 
//Doesn't work because no implicit parameter given of type CanDrink[X]

在 Dotty 中,您可以尝试使用联合类型更改饮料的定义,如 Dmytro Mitin 所建议的:

def drink(x: A | B | C | D)(str: String) = ???
def drink[T](str: String)(using T <:< (A | B | C | D)) = ???

如果需要动态确定,请使用ClassTag

def drink[T](str: String)(implicit ev: ClassTag[T]) = ev match {
  case classOf[A] => ???
  ...
}

如果您实际上覆盖了泛型方法,则必须为所有可能的类型参数类型实现它(否则您违反了类的约定):

trait BearLike {
  def drink[T](str: String)
}

case class Bear(a: String, b: String) extends BearLike {
  override def drink[T](str: String) = ??? // for all T
}

或者

case class Bear(a: String, b: String) {
  def drinkABCD[T](str: String)(implicit can: Can[T]) = can.open(str) // only for A, ..., D
}

或者

case class Bear(a: String, b: String) extends BearLike {
  override def drink[T](str: String): Unit = sys.error("Bear is not actually a BearLike")
  def drinkABCD[T](str: String)(implicit can: Can[T]) = can.open(str) // only for A, ..., D
}

只要有Can[A] , ..., Can[D]

trait Can[T] {
  def open(str: String)
}
object Can {
  implicit val a: Can[A] = ???
  implicit val b: Can[B] = ???
  implicit val c: Can[C] = ???
  implicit val d: Can[D] = ???
}

如果您可以修改合同,那么您可以将此限制(该方法仅适用于A ,..., D )添加到合同中

trait BearLike {
  def drink[T](str: String)(implicit can: Can[T])
}

case class Bear(a: String, b: String) extends BearLike {
  override def drink[T](str: String)(implicit can: Can[T]) = can.open(str)
}

有时将 FP(类型类)与 OOP(继承)结合起来并不容易。 通常,如果您开始使用类型类( Can ),您应该更喜欢类型类

trait BearLike[B] {
  def drink(str: String)
}

case class Bear[T](a: String, b: String) 
object Bear {
  implicit def bearIsBearLike[T](implicit can: Can[T]): BearLike[Bear[T]] = new BearLike[Bear[T]] {
    override def drink(str: String): Unit = can.open(str)
  }
}

如何定义“类型析取”(联合类型)?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM