如何使用 scala class 成员名称作为变量
How to use scala class member name as variable
在 scala 中,有没有办法访问 class 成员,但成员名称是 var?
下面是一个代码片段,有一个名为 "one_star" 的 class 成员。我有一个变量,其值为 "one_star",我想将此变量用作 "case class".
的成员名称
case class Features(
// star about
var one_star: String = "0",
var two_star: String = "0",
var three_star: String = "0",
var four_star: String = "0",
var five_star: String = "0"
// other about
)
object Features {
def apply(): Features = {
val features = new Features()
var testVar = "one_star"
features.${testVar} = "1"
features
}
}
Scala 是静态类型语言,不允许这些语言结构。但是你可以使用反射(硬方式)或模式匹配这样的代码(简单方式):
class Features (
var one_star: String = "0",
var two_star: String = "0",
var three_star: String = "0",
var four_star: String = "0",
var five_star: String = "0") {
def setField(field: String, value: String): Unit = {
field match {
case "one_star" => one_star = value
case "two_star" => two_star = value
case "three_star" => three_star = value
case "four_star" => four_star = value
case "five_star" => five_star = value
}
}
}
这可以使用 scala-reflect
,尽管在大多数情况下我不推荐它。
import scala.reflect.runtime.universe._
val field = typeOf[Features].decl(TermName(testVar)).asTerm.accessed.asTerm
val mirror = runtimeMirror(classOf[Features].getClassLoader)
mirror.reflect(features).reflectField(field).set("1")
您确定不想为您的 class 使用或扩展 Map[String, String]
吗?这么多属性不典型。
如果您想动态更改字段名称,即提供 class 变量名作为值,找到匹配给定变量名的字段,最后更改该字段的值 ,有几种方法:简单的一种是使用模式匹配自行检查字段值并更改实例值和 return 实例。但是,它可能会非常混乱,因为您需要处理 class 中定义的每个字段,如果您有很多字段,它可能会非常麻烦。因此,您将需要一些通用的方法来解决这个问题。
另一种方法是使用 scala 反射。 Scala 反射是为此而设计的,即在运行时像您的情况一样以更通用的方式修改您的代码。以下是更改给定字段名称的实例值的代码片段。
case class Features(
// star about
var one_star: String = "0",
var two_star: String = "0",
var three_star: String = "0",
var four_star: String = "0"
// other about
) {
def copyInstance(variableName: String, value: String): Features = {
// 1. Initialize Features instance
val instance = Features()
// 2. Import scala reflection api.
import scala.reflect.runtime.{universe => ru}
// 3. Get the mirror of instance of Features class.
// Mirror will reflect to instance of Features case class, and we will use this instance mirror to modify its fields value.
val instanceMirror = ru.runtimeMirror(instance.getClass.getClassLoader).reflect(instance)
// 4. Now, Get the field whose value need to be changed - i.e. name you provide - variableName.
val field = ru.typeOf[Features].decl(ru.TermName(variableName)).asTerm
// 5. Get the mirror for that field so that we can read and write to this field.
val fieldMirror = instanceMirror.reflectField(field)
// 6. Finally, set the value to this field.
fieldMirror.set(value)
// 7. Return the changed instance.
instance
}
}
val features = Features()
val changedFeatures = features.copyInstance("one_star", "changed")
println(features)
println(changedFeatures)
//Result
Features(0,0,0,0)
Features(changed,0,0,0)
另请注意,对于提供了无效变量名称和值的情况,您可能需要处理 Exception
。此外,如果您的案例 class 包含 >22 个字段参数,则案例 class 的某些功能将不可用。
在 scala 中,有没有办法访问 class 成员,但成员名称是 var? 下面是一个代码片段,有一个名为 "one_star" 的 class 成员。我有一个变量,其值为 "one_star",我想将此变量用作 "case class".
的成员名称case class Features(
// star about
var one_star: String = "0",
var two_star: String = "0",
var three_star: String = "0",
var four_star: String = "0",
var five_star: String = "0"
// other about
)
object Features {
def apply(): Features = {
val features = new Features()
var testVar = "one_star"
features.${testVar} = "1"
features
}
}
Scala 是静态类型语言,不允许这些语言结构。但是你可以使用反射(硬方式)或模式匹配这样的代码(简单方式):
class Features (
var one_star: String = "0",
var two_star: String = "0",
var three_star: String = "0",
var four_star: String = "0",
var five_star: String = "0") {
def setField(field: String, value: String): Unit = {
field match {
case "one_star" => one_star = value
case "two_star" => two_star = value
case "three_star" => three_star = value
case "four_star" => four_star = value
case "five_star" => five_star = value
}
}
}
这可以使用 scala-reflect
,尽管在大多数情况下我不推荐它。
import scala.reflect.runtime.universe._
val field = typeOf[Features].decl(TermName(testVar)).asTerm.accessed.asTerm
val mirror = runtimeMirror(classOf[Features].getClassLoader)
mirror.reflect(features).reflectField(field).set("1")
您确定不想为您的 class 使用或扩展 Map[String, String]
吗?这么多属性不典型。
如果您想动态更改字段名称,即提供 class 变量名作为值,找到匹配给定变量名的字段,最后更改该字段的值 ,有几种方法:简单的一种是使用模式匹配自行检查字段值并更改实例值和 return 实例。但是,它可能会非常混乱,因为您需要处理 class 中定义的每个字段,如果您有很多字段,它可能会非常麻烦。因此,您将需要一些通用的方法来解决这个问题。
另一种方法是使用 scala 反射。 Scala 反射是为此而设计的,即在运行时像您的情况一样以更通用的方式修改您的代码。以下是更改给定字段名称的实例值的代码片段。
case class Features(
// star about
var one_star: String = "0",
var two_star: String = "0",
var three_star: String = "0",
var four_star: String = "0"
// other about
) {
def copyInstance(variableName: String, value: String): Features = {
// 1. Initialize Features instance
val instance = Features()
// 2. Import scala reflection api.
import scala.reflect.runtime.{universe => ru}
// 3. Get the mirror of instance of Features class.
// Mirror will reflect to instance of Features case class, and we will use this instance mirror to modify its fields value.
val instanceMirror = ru.runtimeMirror(instance.getClass.getClassLoader).reflect(instance)
// 4. Now, Get the field whose value need to be changed - i.e. name you provide - variableName.
val field = ru.typeOf[Features].decl(ru.TermName(variableName)).asTerm
// 5. Get the mirror for that field so that we can read and write to this field.
val fieldMirror = instanceMirror.reflectField(field)
// 6. Finally, set the value to this field.
fieldMirror.set(value)
// 7. Return the changed instance.
instance
}
}
val features = Features()
val changedFeatures = features.copyInstance("one_star", "changed")
println(features)
println(changedFeatures)
//Result
Features(0,0,0,0)
Features(changed,0,0,0)
另请注意,对于提供了无效变量名称和值的情况,您可能需要处理 Exception
。此外,如果您的案例 class 包含 >22 个字段参数,则案例 class 的某些功能将不可用。