Scala 如何测试基本类型的对象集合中是否存在一组类型?

Scala 如何测试基本类型的对象集合中是否存在一组类型?,scala,Scala,我需要将传入对象的类型与一组预定义对象相交 原始方法是扫描每个预定义类型的传入集合: trait Field class Field1 extends Field class Field2 extends Field class Field3 extends Field ... class FieldManager(shownFields:Iterable[Field]) { var hiddenFields = new ArrayBuffer[Field] var found = f

我需要将传入对象的类型与一组预定义对象相交

原始方法是扫描每个预定义类型的传入集合:

trait Field
class Field1 extends Field
class Field2 extends Field
class Field3 extends Field
...

class FieldManager(shownFields:Iterable[Field]) {
  var hiddenFields = new ArrayBuffer[Field]
  var found = false
  for (sf <- shownFields) {
    if (sf.isInstanceOf[Field1]) {
      found = true
      break
    }
  if (!found)
    hiddenFields+=new Field1
  for (sf <- shownFields) {
    if (sf.isInstanceOf[Field2]) {
      found = true
      break
    }
  if (!found)
    hiddenFields+=new Field2
  for (sf <- shownFields) {
    if (sf.isInstanceOf[Field3]) {
      found = true
      break
    }
  if (!found)
    hiddenFields+=new Field3
  ...
}

查找具有给定类型的集合的第一个成员很简单:

shownFields.find(_.isInstanceOf[Field1])
但这仍然会返回一个
Option[Field]
的实例,而不是
Option[Field1]
——这是用于强类型的。collect方法将有助于:

showFields.collect{case x : Field1 => x}
这将返回一个
Iterable[Field1]
,然后您可以使用
headOption
选择Iterable的第一个元素作为
选项[Field1]
,如果存在
Some[Field1]
,否则:

showFields.collect{case x : Field1 => x}.headOption
为了提高效率,并且不计算列表中的所有字段1,我还通过
view
方法将其设置为惰性:

showFields.view.collect{case x : Field1 => x}.headOption
如果未找到默认值,则使用选项提供的
getOrElse
方法提供默认值:

showFields.view.collect{case x : Field1 => x}.headOption getOrElse (new Field1)
更新

我只是回顾一下这个问题,如果您希望hiddenFields包含每个字段子类型的新实例,而showFields中没有成员

要查找
Iterable
中表示的所有类型,请执行以下操作:

val shownFieldTypes = showFields.map(_.getClass).toSet
(将其转换为集合将强制使用唯一值)

如果您有一组感兴趣的字段:

val allFieldTypes = Set(classOf[Field1], classOf[Field2], ...)
您可以通过减法查找缺少的项:

val hiddenFieldTypes = allFieldTypes -- shownFieldTypes
这里的问题是,使用newInstance时,您会陷入困境,而反射并不总是可取的。。。因此:

val protoHiddenFields = Set(new Field1, new Field2, ...)
val allFieldTypes = protoHiddenFields.map(_.getClass)
val hiddenFieldTypes = allFieldTypes -- shownFieldTypes
val hiddenFields = protohiddenFields.filter(hiddenFieldTypes contains _.getClass)

这种方法的优点在于,可以使用构造函数参数初始化原型,如果您愿意,可以维护一组已知的
字段的子类,如下所示:

val allFieldClasses = Set[Class[_ <: Field]](
  classOf[Field1], 
  classOf[Field2],
  classOf[Field3],
  ...)

不幸的是,当您添加
字段
的新子类时,您必须记住保持
所有字段类
的最新状态——编译器不会警告您集合不完整——但我看没有办法解决这一问题。

对于第一种类型的序列来说太长了。顺便说一句,我的类不是case类(不推荐使用无参数构造函数的case类)。但我不是指任何地方的case类。。。案例类在伴生对象中有一个unapply方法,这使它们更容易用于模式匹配,但它们肯定不是模式匹配中唯一可以使用的东西!我接受这一点,因为它首先提到了类型列表,并且似乎实际使用编译器()进行了测试。是的,这有点难看,因为getClass()是在所有对象上定义的Java方法,因此无法知道返回的类类型的类型参数。
val hiddenFieldTypes = allFieldTypes -- shownFieldTypes
val protoHiddenFields = Set(new Field1, new Field2, ...)
val allFieldTypes = protoHiddenFields.map(_.getClass)
val hiddenFieldTypes = allFieldTypes -- shownFieldTypes
val hiddenFields = protohiddenFields.filter(hiddenFieldTypes contains _.getClass)
val allFieldClasses = Set[Class[_ <: Field]](
  classOf[Field1], 
  classOf[Field2],
  classOf[Field3],
  ...)
def createHiddenFields(shownFields: Iterable[Field]):Set[Field] = {
  val toClass = (_:Field).getClass.asInstanceOf[Class[Field]]
  (allFieldTypes -- (shownFields map toClass)) map (_.newInstance)
}