匹配共变表

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

我有一个基类(让我们把它命名为 Base)和多个扩展类和方法进行验证。validate 它接受 Any.

我想检查参数是否是Base的子类,这样我就可以调用 validate 方法,如果它是List of instances of subclass of Base也要这样做。

我试过下面的代码,但这不能编译。有没有一种简单、优雅的方法?

class Base {
  def validate(): Unit = {}
}

class Extended1 extends Base {
  override def validate(): Unit = {
    // some checks
  }
}

def validate(param: Any): Unit = {
  param match {
    case b: Base => b.validate()

    // this is not working
    case l: List[+Base] => l.foreach(_.validate())

    case _ => // do nothing
  }
}

UPDATE:我可以使用方法的重载。我还有一些检查,我从问题中删除了,这是错误的,对不起。

那么,我有一个基类(让我们来看看)。

def validate(param: Any): Unit = {
  if (Option(param).isEmpty) throwMissingReqFieldException(param)
  param match {
    case b: Base => b.validate()
    case _ =>
  }
}

def validate(param: List[Any]): Unit = {
  if (Option(param).isEmpty || fieldValue.isEmpty) throwMissingReqFieldException(param)
  // here I would like to recursively call validate if possible, maybe this is the solution
  param.foreach(x => validate(x))
}
scala covariance
1个回答
3
投票

尝试与类型类的方法

trait Validate[T] {
  def validate(t: T): Unit
}
object Validate {
  implicit def defaultValidate[T]: Validate[T] = _ => ()
  implicit val baseValidate: Validate[Base] = _.validate()
  implicit def baseListValidate[B <: Base]: Validate[List[B]] = _.foreach(_.validate())
}

def validate[T](param: T)(implicit v: Validate[T]): Unit = v.validate(param)

1
投票

如果你绝对需要一个 Any 作为参数,这样做。

def validate(param: Any): Unit = {
  param match {
    case b: Base => b.validate()
    case l: List[Base] => if (list.forall(_.isInstanceOf[Base])) l.foreach(_.validate())
    case _ => // do nothing
  }
}

这里 [Base] 部分实际上是无用的,但它告诉编译器把你的列表当作一个 List[Base]. 实际的检查是在if语句中,你要确保所有的对象都是 Base 对象。

你也可以做 l.foreach(b => if (b.isInstanceOf[Base]) validate(b)) 如果你不在乎列表中不只包含了 Base的,也可能包含 String

不过,更好的办法是超载。

def validate(b: Base): Unit = b.validate()
def validate(l: List[Base]): Unit = l.foreach(validate)
© www.soinside.com 2019 - 2024. All rights reserved.