确定子类中的非空附加字段
Determine non-empty additional fields in a subclass
假设我有一个看起来像这样的特征
trait MyTrait {
val x: Option[String] = None
val y: Option[String] = None
}
Post 定义特征我将这个特征扩展到 class MyClass
看起来像这样
case class MyClass(
override val x: Option[String] = None,
override val y: Option[String] = None,
z: Option[String] = None
) extends MyTrait
现在我需要找出除 MyTrait
扩展的属性之外的任何其他 属性 是否不是 None
。从某种意义上说,如果我需要编写一个名为 getClassInfo
的方法,其中 returns true/false 基于案例 class 中存在的值。在这种情况下,如果 z
是非可选的,它应该 return 为真。我的 getClassInfo
是这样的
def getClassInfo(myClass: MyClass): Boolean = {
myClass
.productIterator
.filterNot(x => x.isInstanceOf[MyTrait])
.exists(_.isInstanceOf[Some[_]])
}
在这种情况下,理想情况下,这应该过滤掉不属于 Mytrait
和 return 我 z
的所有字段。
我尝试使用方差,但似乎 isInstanceOf
不采用相同的
filterNot(x => x.isInstanceOf[+MyTrait])
然而这是不可能的
val a = getClassInfo(MyClass()) //Needs to return false
val b = getClassInfo(MyClass(Some("a"), Some("B"), Some("c"))) //returns true
val c = getClassInfo(MyClass(z = Some("z"))) //needs to return true
val d = getClassInfo(MyClass(x = Some("x"), y = Some("y"))) // needs to return false
简单的答案是声明一个给出你想要的结果的抽象方法并在子类中覆盖它:
trait MyTrait {
def x: Option[String]
def y: Option[String]
def anyNonEmpty: Boolean = false
}
case class MyClass(x: Option[String] = None, y: Option[String] = None, z: Option[String] = None) extends MyTrait {
override def anyNonEmpty = z.nonEmpty
}
然后您可以在您的对象上调用 anyNonEmpty
以获得 getClassInfo
结果。
另请注意,我在 trait
中使用了 def
,因为 trait
中的 val
由于初始化问题通常不是一个好主意。
如果你真的需要反射可以试试
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
def getClassInfo(myClass: MyClass): Boolean = {
def fields[A: TypeTag] = typeOf[A].members.collect {
case m: MethodSymbol if m.isGetter && m.isPublic => m
}
val mtFields = fields[MyTrait]
val mcFields = fields[MyClass]
val mtFieldNames = mtFields.map(_.name).toSet
val mcNotMtFields = mcFields.filterNot(f => mtFieldNames.contains(f.name))
val instanceMirror = currentMirror.reflect(myClass)
val mcNotMtFieldValues = mcNotMtFields.map(f => instanceMirror.reflectField(f).get)
mcNotMtFieldValues.exists(_.isInstanceOf[Some[_]])
}
val a = getClassInfo(MyClass()) //false
val b = getClassInfo(MyClass(Some("a"), Some("B"), Some("c"))) //true
val c = getClassInfo(MyClass(z = Some("z"))) //true
val d = getClassInfo(MyClass(x = Some("x"), y = Some("y")))//false
假设我有一个看起来像这样的特征
trait MyTrait {
val x: Option[String] = None
val y: Option[String] = None
}
Post 定义特征我将这个特征扩展到 class MyClass
看起来像这样
case class MyClass(
override val x: Option[String] = None,
override val y: Option[String] = None,
z: Option[String] = None
) extends MyTrait
现在我需要找出除 MyTrait
扩展的属性之外的任何其他 属性 是否不是 None
。从某种意义上说,如果我需要编写一个名为 getClassInfo
的方法,其中 returns true/false 基于案例 class 中存在的值。在这种情况下,如果 z
是非可选的,它应该 return 为真。我的 getClassInfo
是这样的
def getClassInfo(myClass: MyClass): Boolean = {
myClass
.productIterator
.filterNot(x => x.isInstanceOf[MyTrait])
.exists(_.isInstanceOf[Some[_]])
}
在这种情况下,理想情况下,这应该过滤掉不属于 Mytrait
和 return 我 z
的所有字段。
我尝试使用方差,但似乎 isInstanceOf
不采用相同的
filterNot(x => x.isInstanceOf[+MyTrait])
然而这是不可能的
val a = getClassInfo(MyClass()) //Needs to return false
val b = getClassInfo(MyClass(Some("a"), Some("B"), Some("c"))) //returns true
val c = getClassInfo(MyClass(z = Some("z"))) //needs to return true
val d = getClassInfo(MyClass(x = Some("x"), y = Some("y"))) // needs to return false
简单的答案是声明一个给出你想要的结果的抽象方法并在子类中覆盖它:
trait MyTrait {
def x: Option[String]
def y: Option[String]
def anyNonEmpty: Boolean = false
}
case class MyClass(x: Option[String] = None, y: Option[String] = None, z: Option[String] = None) extends MyTrait {
override def anyNonEmpty = z.nonEmpty
}
然后您可以在您的对象上调用 anyNonEmpty
以获得 getClassInfo
结果。
另请注意,我在 trait
中使用了 def
,因为 trait
中的 val
由于初始化问题通常不是一个好主意。
如果你真的需要反射可以试试
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
def getClassInfo(myClass: MyClass): Boolean = {
def fields[A: TypeTag] = typeOf[A].members.collect {
case m: MethodSymbol if m.isGetter && m.isPublic => m
}
val mtFields = fields[MyTrait]
val mcFields = fields[MyClass]
val mtFieldNames = mtFields.map(_.name).toSet
val mcNotMtFields = mcFields.filterNot(f => mtFieldNames.contains(f.name))
val instanceMirror = currentMirror.reflect(myClass)
val mcNotMtFieldValues = mcNotMtFields.map(f => instanceMirror.reflectField(f).get)
mcNotMtFieldValues.exists(_.isInstanceOf[Some[_]])
}
val a = getClassInfo(MyClass()) //false
val b = getClassInfo(MyClass(Some("a"), Some("B"), Some("c"))) //true
val c = getClassInfo(MyClass(z = Some("z"))) //true
val d = getClassInfo(MyClass(x = Some("x"), y = Some("y")))//false