【问题标题】:How can I resolve type error on compile: Any to T?如何解决编译时的类型错误:Any to T?
【发布时间】:2020-12-28 09:03:54
【问题描述】:

我有一个用于 Tuple 的 json 序列化程序。它首先反映元组并构建一个函数,给定一个元组,它将返回一个 (TypeAdapter, value) 对的列表。 (TypeAdapter 是呈现值的特定类型的东西。)看起来像这样:

def extractTuple(p: Product): (Product)=>List[(TypeAdapter[_], Any)] = {
  val reflected = reflectOnTuple(tupleClass)  // extract a bunch of reflected metadata
  val tupleFieldInfo = reflected.tupleFieldInfo
  tupleFieldInfos match {
    case 1 =>
      (p: Product) => 
        List( (getTypeAdapterFor(tupleFieldInfo(0)), p.asInstanceOf[Tuple1[_]]._1) )
    case 2 =>
      (p: Product) => 
        List( (getTypeAdapterFor(tupleFieldInfo(0)), p.asInstanceOf[Tuple1[_]]._1),
          (getTypeAdapterFor(tupleFieldInfo(1)), p.asInstanceOf[Tuple1[_]]._2) )
    //... and so on to Tuple23
  }
}

在 JSON 序列化程序中,我有一个 writeTuple() 函数,如下所示。理论上它应该按原样工作,但是......我在 fieldValue 上遇到编译错误,说它是 Any 类型,而预期的是 ?1.T.

TypeAdapter 看起来像:

trait TypeAdapter[T] {
  def write[WIRE](
      t:      T,
      writer: Writer[WIRE],
      out:    mutable.Builder[WIRE, WIRE]): Unit
}
class JsonWriter() {
  def writeTuple[T](t: T, writeFn: (Product) => List[(TypeAdapter[_], Any)], out: mutable.Builder[JSON, JSON]): Unit = {
    out += "[".asInstanceOf[JSON]
    var first = true
    writeFn(t.asInstanceOf[Product]).foreach { case (fieldTA, fieldValue) =>
      if (first)
        first = false
      else
        out += ",".asInstanceOf[JSON]
      fieldTA.write(fieldValue, this, out) // <<-- this blows up (compile) on fieldValue because it's type Any, not some specific field Type
    }
    out += "]".asInstanceOf[JSON]
  }
}

如何让我的 TypeAdapter 相信该字段是正确的类型?

【问题讨论】:

  • 你不会在任何地方使用extractTuple

标签: scala generics existential-type


【解决方案1】:

尝试将类型模式与类型变量tp(小写)一起使用

class JsonWriter() extends Writer[JSON] {
  def writeTuple[T](t: T, writeFn: (Product) => List[(TypeAdapter[_], Any)], out: mutable.Builder[JSON, JSON]): Unit = {
    ...
    writeFn(t.asInstanceOf[Product]).foreach { case (fieldTA: TypeAdapter[tp], fieldValue) =>
      ...
      fieldTA.write(fieldValue.asInstanceOf[tp], this, out)
    }
    ...
  }
}

T 代替它

class JsonWriter() extends Writer[JSON] {
  def writeTuple[T](t: T, writeFn: (Product) => List[(TypeAdapter[_], Any)], out: mutable.Builder[JSON, JSON]): Unit = {
    ...
    writeFn(t.asInstanceOf[Product]).foreach { case (fieldTA: TypeAdapter[T], fieldValue) =>
      ...
      fieldTA.write(fieldValue.asInstanceOf[T], this, out)
    }
    ...
  }
}

看来您实际上并没有在writeTuple[T] 中使用T。也许您可以尝试单态def writeTuple(t: Product... 此外,如果您想在元组的两个元素中指定(TypeAdapter[_], Any) 实际上是(TypeAdapter[U], U) 和相同的U,您可以尝试存在类型(TypeAdapter[U], U) forSome {type U}。所以试试

class JsonWriter() extends Writer[JSON] {
  def writeTuple(t: Product, writeFn: (Product) => List[(TypeAdapter[U], U) forSome {type U}], out: mutable.Builder[JSON, JSON]): Unit = {
    out += "[".asInstanceOf[JSON]
    var first = true
    writeFn(t).foreach { case (fieldTA, fieldValue) =>
      if (first)
        first = false
      else
        out += ",".asInstanceOf[JSON]
      fieldTA.write(fieldValue, this, out)
    }
    out += "]".asInstanceOf[JSON]
  }
}

【讨论】:

    【解决方案2】:

    Dmytro,你的答案非常接近!不幸的是,第一个或第二个选项都没有编译。我认为第 3 种会很好用,除了...我实际上使用的是 Dotty 而不是 Scala,而且 Dotty 消除了存在类型。

    所以我尝试了以下方法,并且成功了。它涉及修改 TypeAdapter,因为它知道它的类型:

    trait TypeAdapter[T] {
      type tpe = T
      def write[WIRE](
          t:      T,
          writer: Writer[WIRE],
          out:    mutable.Builder[WIRE, WIRE]): Unit
      inline def castAndWrite[WIRE]( 
          v:      Any, 
          writer: Writer[WIRE], 
          out:    mutable.Builder[WIRE, WIRE]): Unit = 
        write(v.asInstanceOf[tpe], writer, out)
    }
    

    从 JsonWriter 调用 castAndWrite() 可以调用正确类型的 write() 机制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-17
      • 1970-01-01
      • 2013-03-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多