假设User
有一个案例类,其中包含有关用户的信息:
case class User(name: String, age: Int)
给定一个字段名称(例如"name"
或"age"
),我想返回一个提取该字段的函数(无需再次解析该字段名称)。简而言之,我需要这样做:
val u = User(name = "john",age = 44)
val func = extractFunctionFromFieldName("name") // returns func: User => Any
func(u) // return "john"
阅读有关反射的内容后,我得到了类似的工作:
def extractFunctionFromFieldName(s: String): User => Any = {
val f = classOf[User].getDeclaredField(s)
f.setAccessible(true)
u: User => f.get(u)
}
问题在于此功能不可序列化,因为java.lang.reflect.Field
不可序列化。
有什么建议或选择吗?
备注/更多背景:
{name,age}
而且还在不断增长。这就是为什么我要避免硬编码productElement
应该没有序列化问题,因为字段已被数字替换。但我知道不能保证产品元素的顺序。使用productElement应该可以解决序列化问题,因为字段已被数字替换。但我知道不能保证产品元素的顺序。
有。对于案例类,它们的顺序与参数相同。
或者,您可以创建一个类,该类仍然可以是一个函数(这里有点通用;如果不需要,更改为User
仅使用它应该很容易):
case class ExtractField[T](s: String)(implicit t: ClassTag[T]) extends (T => Any) {
@transient lazy val f = {
val f = t.runtimeClass.getDeclaredField(s)
f.setAccessible(true)
f
}
def apply(x: T) = f.get(x)
}
这将仅在第一次应用该字段时初始化该字段,因此可以在将其反序列化一次后多次应用而无需重复getDeclaredField
调用。
最初我没有注意到这已经是问题所必需的,因此我最初提供的另一种解决方案不适用:您可以f
在函数内部移动(在这种情况下,f
当您创建函数对象并“捕获”时已经知道了)它,这就是为什么必须对其进行序列化的原因):
def extractFunctionFromFieldName(s: String): User => Any = { u: User =>
val f = classOf[User].getDeclaredField(s)
f.setAccessible(true)
f.get(u)
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句