scala 类型删除和值类

标签 scala type-erasure

我试图绕过类型删除,并使用值类将不同类型的值列表动态转换为 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]。这永远不会起作用。一旦您丢失了映射中的类型信息,您就无法在不处理某种无效值的情况下构建 FieldMyVal 。您希望明确保留这些值只是允许的值的信息,这就是 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/

相关文章:

java - Scala 函数对象之间的隐式转换?

scala - 如何在 Scala Actor 模型中重载 bang(!) 运算符?

Scala isInstanceOf 和类型删除

Scala:具有多个来源和异构类型的交叉(笛卡尔)积

java - 如何避免在 Java 泛型扩展 Comparable 接口(interface)中进行未经检查的强制转换?

Scala - 无法将 Scala 对象写入 Cassandra

Scala - 类型不匹配;找到 Int,需要 String

python - 如何将键值对减少为键和值列表?

java - 为什么 Java(但不是 .NET)无法在不需要原始类型/类型删除的情况下适应泛型?

c++ - 使编译器在类型删除中使用 lambda 优化函数调用间接