假设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
应该可以在没有序列化问题的情况下工作,因为字段会被数字替换。但据我所知,产品元素的顺序无法保证。答案 0 :(得分:2)
使用productElement应该没有序列化问题,因为字段被数字替换。但据我所知,产品元素的顺序无法保证。
有。对于案例类,它们将与参数的顺序相同。
或者你可以创建一个类,它仍然可以是一个函数(在这里更常见;如果不需要,更改为使用wow.min.js
只应该很容易):
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