如何处理函数参数中的未定义类对象?JsonMethods.extract用法咨询
你的代码报错的核心原因是JsonMethods.extract需要编译时就能确定的具体类型,而你传入的a是Any类型,编译器没法知道要提取成什么类型,自然会报错。下面分两种场景给你解决方案,对应你的需求:
场景1:你想根据传入实例的类型,生成该类型的新实例
如果只是想从JSON提取出和传入对象同类型的新实例,用Scala的Manifest/TypeTag来保留运行时类型信息就可以了。Json4s的extract方法依赖Manifest来获取类型信息,我们可以把函数改成泛型函数,加上上下文界定:
import org.json4s._ import org.json4s.jackson.JsonMethods._ import scala.reflect.Manifest // 用上下文界定[T: Manifest]让编译器自动传入Manifest def func[T: Manifest](a: T) { val json = """{"c_1":"hi","c_2":"bye"}""" // 现在extract能正确识别T的类型了 val newInstance = parse(json).extract[T] println(newInstance.c_1) // 输出 "hi" } // 调用方式和你期望的一样 case class Test(var c_1: String, var c_2: String) val t = Test("", "") func(t)
这里的[T: Manifest]是Scala的语法糖,等价于在参数列表里加implicit m: Manifest[T],编译器会自动为传入的Test类型生成对应的Manifest,让extract能正确反序列化。
场景2:你想修改传入的实例(而不是生成新实例)
看你的示例,你期望调用func(t)后,原来的t对象的字段值被更新成JSON里的值。但extract是创建新实例,不会修改原有对象,这时候需要用Scala反射API来手动设置字段值:
import org.json4s._ import org.json4s.jackson.JsonMethods._ import scala.reflect.runtime.universe._ def func[T: TypeTag](a: T) { val json = """{"c_1":"hi","c_2":"bye"}""" // 把JSON解析成键值对Map val jsonValues = parse(json).values.asInstanceOf[Map[String, Any]] // 获取反射镜像,用于操作实例字段 val mirror = runtimeMirror(getClass.getClassLoader) val instanceMirror = mirror.reflect(a) // 遍历JSON的键值对,设置到实例的对应字段 jsonValues.foreach { case (fieldName, value) => // 获取字段的符号信息 val fieldSymbol = typeOf[T].decl(TermName(fieldName)).asTerm // 获取字段的镜像,用于设置值 val fieldMirror = instanceMirror.reflectField(fieldSymbol) // 设置字段值 fieldMirror.set(value) } } // 调用后原有实例的字段会被更新 case class Test(var c_1: String, var c_2: String) val t = Test("", "") func(t) println(t.c_1) // 输出 "hi" println(t.c_2) // 输出 "bye"
注意:这里你的case class必须用var修饰字段(你已经这么做了),因为反射只能修改可变字段;如果是val的话,字段是不可变的,没法修改。
关于“处理未定义类对象”的问题
如果你的函数需要处理完全未知的类(编译时不知道具体类型),可以直接传递Class[_]参数,或者从传入的Any对象获取Class:
def func(a: Any) { val json = """{"c_1":"hi","c_2":"bye"}""" // 从对象获取Class,然后提取实例 val instance = parse(json).extract(a.getClass) // 这里instance是Any类型,后续可以用反射操作它的字段 }
这种方式下,你只能把提取后的实例当成Any来处理,要操作字段还是需要反射,和场景2的后半部分逻辑一致。
内容的提问来源于stack exchange,提问作者Dogil
相关产品推荐
相关产品推荐

