我试图绕过类型删除,并使用值类将不同类型的值列表动态转换为 json,然后使用 Json4s CustomSerializer 将其转换回相应的类型。但是,我无法动态提取正确的值。由于引用 AnyVal,我在转换为 Json 时被迫使用 value.toString,并且在从 json 重新创建字段时遇到问题。
我已经尝试 scala 三周了,所以我仍在学习诀窍。任何帮助将不胜感激。
abstract class MyVal {
def name: String
def value: AnyVal
}
trait Field {
def value: AnyVal
}
object Field {
def build(value: String): MyString = MyString(value)
def build(value: Int): MyInt = MyInt(value)
def build(value: Double): MyDouble = MyDouble(value)
}
case class MyString(val value: String) extends AnyVal with Field
case class MyInt(val value: Int) extends AnyVal with Field
case class MyDouble(val value: Double) extends AnyVal with Field
object MyVal {
case class StringVal(name: String, value: MyString) extends MyVal
case class IntVal(name: String, value: MyInt) extends MyVal
case class DoubleVal(name: String, value: MyDouble) extends MyVal
def build(name: String, value: String): StringVal = StringVal(name, MyString(value))
def build(name: String, value: Int): IntVal = IntVal(name, value)
def build(name: String, value: Double): DoubleVal = DoubleVal(name, value)
}
object Main {
def main(args: Array[String]) = {
var fields = Seq.empty[MyVal]
var row = Map("length" -> 1, "name" -> "test", "cost" -> 2.0)
var columns = Seq[String]("length", "name", "cost")
val fields: Seq[MyVal] = row foldLeft (Seq.empty[MyVal]) {
(previousFields: Seq[MyVal], currentField: Any) => {
columns map {
column => MyVal.build(column, Field.build(row(column)))
}
}
}
}
}
由于不明确,构建方法无法正确解析。
最佳答案
Field
特征定义了字段的所有可能类型:
import scala.language.existentials
import scala.language.implicitConversions
sealed trait Field extends Any {
def value: Any
}
case class MyString(val value: String) extends AnyVal with Field
case class MyInt(val value: Int) extends AnyVal with Field
case class MyDouble(val value: Double) extends AnyVal with Field
请注意下面隐式的 def
。它们允许将已知类型的值转换为 Field
,而无需显式使用 build
。我们将在下面利用它。
object Field {
implicit def build(value: String): MyString = MyString(value)
implicit def build(value: Int): MyInt = MyInt(value)
implicit def build(value: Double): MyDouble = MyDouble(value)
}
对于MyVal
,我们不需要特定的子类 - 这只会复制Field
的层次结构。足以说明每个值都与一个 Field
关联 - 这捕获相同的信息。
sealed case class MyVal(name: String, value: Field)
我们仍然可以定义隐式,以便能够更轻松地构建 MyVal
,尽管我们不需要这样做。
object MyVal {
// notice that we use the above Field.build.. implicits here:
implicit def build(name: String, value: String): MyVal = MyVal(name, value)
implicit def build(name: String, value: Int): MyVal = MyVal(name, value)
implicit def build(name: String, value: Double): MyVal = MyVal(name, value)
}
我不太确定您想在 main
函数中表达什么。下面是更简单的例子。这里的主要技巧是您不想拥有Map[String,Any]
。这永远不会起作用。一旦您丢失了映射中的类型信息,您就无法在不处理某种无效值的情况下构建 Field
和 MyVal
。您希望明确保留这些值只是允许的值的信息,这就是 Field
的用途。通过声明Map[String,Field]
并让隐式
为您完成无聊的工作,您将获得下面的类型安全代码:
object Main {
def main(args: Array[String]) = {
val row = Map[String,Field]("length" -> 1, "name" -> "test", "cost" -> 2.0)
val vals: Seq[MyVal] = (for((k, v) <- row.iterator) yield MyVal(k, v)).toSeq
}
}
特别是,您希望避免处理类型删除。类型化代码是你的优势,类型删除应尽可能留给运行时。
关于scala 类型删除和值类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30284096/