Scala:如何检查是否至少定义了 class 的一个字段?
Scala: How to check if at least one of the fields of a class is defined?
我有一个 class,它有几个可选字段,如下所示:
class Container(f1: Option[String] = None,
f2: Option[Boolean] = None,
f3: Option[Int] = None,
f4: Option[String] = None
// ... 30 other fields which is unfortunate/terrible and
// cannot be changed at the moment
) {
def hasAtleastOneDefinedField: Boolean = {
this.f1.isDefined ||
this.f2.isDefined ||
this.f3.isDefined ||
this.f4.isDefined
// this is too-much of boilerplate
}
// This is something along the lines of what I want
def hasAtleastOneDefinedField2: Boolean = {
// this.getAllDeclaredFields.find(field => field.value.isDefined)
???
}
}
是否可以在不使用反射的情况下做同样的事情?
不确定这能为您节省多少,但是:
val hasAtLeastOneDefinedField = List(f1, f2, f3, ..., f35).exists { _.isDefined }
不要认为还有 reflection/macros 以外的方法。
只是一个想法,但根据您的预期用途,可能有一些值得考虑的设计模式可以让您的意图更加清晰。
例如,如果您正在尝试确定是否有足够的数据来构造某些东西,那么一种选择是构建器模式,例如:
object ContainerBuilder() {
def fromF1(f1: F1) = Container(f1 = Some(f1))
def fromF2(f2: F2) = Container(f2 = Some(f2))
...
}
如果您只允许以这种方式构建 Container 实例(例如,Container class' 构造函数仅对构建器可见),您可以确定它们将恰好具有一个字段集(那里有多种方法可以扩展它以生成具有多个字段集的容器,例如见下文)。
这可以扩展到,例如,确保在创建容器之前设置两个、三个……所有字段。例如:
class ContainerBuilder(f1: Option[String] = None,
f2: Option[Boolean] = None,
f3: Option[Int] = None,
f4: Option[String] = None,
...,
fieldsSet = 0) {
// return a copy of this ContainerBuilder - holding any fields already set -
// with f1 now set, and the count of set fields incremented:
def fromF1(f1: F1) = copy(f1 = Some(f1), fieldsSet = fieldsSet + 1)
// Likewise but setting the f2 field:
def fromF2(f2: F2) = copy(f2 = Some(f2), fieldsSet = fieldsSet + 1)
...
def build = if (readyToBuild) Container(f1,f2,...) else ... // for 'unready' cases, you can throw an exception, or change build to return an Option[Container], or whatever.
def readyToBuild = fieldsSet > 2 // Ensures at least 3 fields set - change to whatever criteria you need.
}
还有几种表达方式:
val o1 = None
val o2 = None
val o3 = Option("o")
o1.orElse(o2).orElse(o3).isDefined
List(o1, o2, o3).flatten.nonEmpty
我有一个 class,它有几个可选字段,如下所示:
class Container(f1: Option[String] = None,
f2: Option[Boolean] = None,
f3: Option[Int] = None,
f4: Option[String] = None
// ... 30 other fields which is unfortunate/terrible and
// cannot be changed at the moment
) {
def hasAtleastOneDefinedField: Boolean = {
this.f1.isDefined ||
this.f2.isDefined ||
this.f3.isDefined ||
this.f4.isDefined
// this is too-much of boilerplate
}
// This is something along the lines of what I want
def hasAtleastOneDefinedField2: Boolean = {
// this.getAllDeclaredFields.find(field => field.value.isDefined)
???
}
}
是否可以在不使用反射的情况下做同样的事情?
不确定这能为您节省多少,但是:
val hasAtLeastOneDefinedField = List(f1, f2, f3, ..., f35).exists { _.isDefined }
不要认为还有 reflection/macros 以外的方法。
只是一个想法,但根据您的预期用途,可能有一些值得考虑的设计模式可以让您的意图更加清晰。
例如,如果您正在尝试确定是否有足够的数据来构造某些东西,那么一种选择是构建器模式,例如:
object ContainerBuilder() {
def fromF1(f1: F1) = Container(f1 = Some(f1))
def fromF2(f2: F2) = Container(f2 = Some(f2))
...
}
如果您只允许以这种方式构建 Container 实例(例如,Container class' 构造函数仅对构建器可见),您可以确定它们将恰好具有一个字段集(那里有多种方法可以扩展它以生成具有多个字段集的容器,例如见下文)。
这可以扩展到,例如,确保在创建容器之前设置两个、三个……所有字段。例如:
class ContainerBuilder(f1: Option[String] = None,
f2: Option[Boolean] = None,
f3: Option[Int] = None,
f4: Option[String] = None,
...,
fieldsSet = 0) {
// return a copy of this ContainerBuilder - holding any fields already set -
// with f1 now set, and the count of set fields incremented:
def fromF1(f1: F1) = copy(f1 = Some(f1), fieldsSet = fieldsSet + 1)
// Likewise but setting the f2 field:
def fromF2(f2: F2) = copy(f2 = Some(f2), fieldsSet = fieldsSet + 1)
...
def build = if (readyToBuild) Container(f1,f2,...) else ... // for 'unready' cases, you can throw an exception, or change build to return an Option[Container], or whatever.
def readyToBuild = fieldsSet > 2 // Ensures at least 3 fields set - change to whatever criteria you need.
}
还有几种表达方式:
val o1 = None
val o2 = None
val o3 = Option("o")
o1.orElse(o2).orElse(o3).isDefined
List(o1, o2, o3).flatten.nonEmpty