【问题标题】:Scala trouble with casting to genericsScala 在转换为泛型时遇到问题
【发布时间】:2014-10-29 08:31:34
【问题描述】:

我尝试编写一些根据输入类型执行不同操作的函数。 例如,我这样做:

def Foo[T](inList: List[String]): ArrayBuffer[T] = {
  val out: ArrayBuffer[T] = new ArrayBuffer[T]()
  inList.map ( x => {
    val str = x.substring(1)
    out += str.asInstanceOf[T]
  })
  out
}

但是如果我用Foo[Long](new List("123","2342")) 调用这个函数,我会得到一个ArrayBufferStrings,而不是Longs。对不起,我的菜鸟问题,我想了解 scala 和泛型。

【问题讨论】:

  • 你在 REPL 中检查过你的代码吗?一切看起来都很好。 scala.collection.mutable.ArrayBuffer[Long] = ArrayBuffer(23, 342)
  • 不知道目标是什么,但强制转换破坏了类型安全。
  • 您的ArrayBuffer 对您没有多大帮助。为什么不只返回列表映射的结果(使用答案中提到的转换器函数之一)?

标签: scala generics casting


【解决方案1】:
  1. Scala 运行在 JVM 之上,它对泛型一无所知,并且泛型的具体类型在运行时不可用。

因此,您的代码的运行时等效项将如下所示

  def Foo(inList: List[String]): (ArrayBuffer[Object]) = {
    val out: ArrayBuffer[Object] = new ArrayBuffer[Object]()
    inList.map ( x => {
      val str=x.substring(1)
      out += str.asInstanceOf[Object]
    })
    (out)
  }
  1. asInstanceOf 不会将字符串转换为 long,而是会抛出有关不兼容类型的异常。相反,您应该为您的函数提供从字符串到另一种类型的转换。

总结一下,你的代码应该是这样的:

  import scala.collection.mutable.ArrayBuffer

  // here we define how convert string to longs
  implicit def stringToLong(s: String) = s.toLong

  // now this function requires to have converter from string to T in context
  def Foo[T](inList: List[String])(implicit f: (String) => T): (ArrayBuffer[T]) = {
    val out: ArrayBuffer[T] = new ArrayBuffer[T]()
    inList.map { x => 
      val str = x.substring(1)
      out += f(str) // here we apply converter
    }
    out
  }

  // when function is called, appropriate implicit converter from context will be used
  Foo[Long](List("51", "42"))

【讨论】:

    【解决方案2】:

    String 转换为Long 不会使其成为Long,这是一个错误,因此您应该得到一个运行时错误,指出您不能将String 转换为Long。由于 T 对它可以是什么没有任何限制,因此您不能期望调用不在所有对象上的任何方法(例如toString)。您可以自己提供该功能(这几乎是 map 的确切签名,因此您可以使用它):

    def convert[T](in: List[String])(convert: String => T): List[T] =
      in.map(convert)
    

    或者确保对象属于你知道方法的类型(使用类型绑定):

    trait CanConvertTo[T] {
      def convert: T
    }
    
    case class Example(value: String) extends CanConvertTo[Long] {
      def convert = value.toLong
    }
    
    def convert[T](in: List[CanConvertTo[T]]): List[T] = in.map(_.convert)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-16
      • 1970-01-01
      • 1970-01-01
      • 2019-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多