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)
}