0

我一直在寻找实现这一点,即使使用 Manifest 和 Reflect API,仍然很难实现。

使用 Manifest 和 Reflection,我可以将 List[Any] 匹配到一个类(List[A]),我还可以通过类型 T 进行匹配,就像在 http://daily-scala.blogspot.co.uk/ 2010/01/overcoming-type-erasure-in-matching-1.html

如何保存 TypeTag 然后稍后使用它将类型重新附加到 Any (Scala 2.10)

但是我怎样才能确定输入的类型并在方法中使用它呢?

说,

object test {

val list : List[List[Any]] = List(
  List(2.5, 3.6 ,7.9),
  List("EUR","HKD", "USD")
)

def calculateString(in:List[String]) = {
  println("It's a String List")
  println(in)
}

  def calculateDouble(in:List[String]) = {
    println("It's a Double List")
    println(in)
  }

  def main( args: Array[String]){
    list.foreach(l=> matchAndCalculate(l))
  }


  // Copy from Andrzej Jozwik it doesn't work, but it's good to demonstrate the idea
  def matchAndCalculate(list:List[Any]) = list match {
    case i if i.headOption.exists(_.isInstanceOf[Long]) =>  calculateLong(i)
    case i if i.headOption.exists(_.isInstanceOf[String]) =>  calculateString(i)
  }

}

非常感谢

哈维

PS:正如莎拉指出的那样,在我将它们放入更复杂的结构之前,这可能是在我首先创建列表时保持类型清单的唯一方法。

这是挑战:是否可以将 List[Any] 转换回/匹配到 List[String] 并作为 def dummyMethod(stringList: List[String]) 等方法的输入而不会惹恼编译器?

4

2 回答 2

1

除非您可以更改数据结构,否则 Andrej 的解决方案是唯一合理的方法。

您不能真正使用类型清单,因为您有两个间接级别。对于外部列表的每个成员,您都需要不同类型的清单。例如,您可以有 a List[(List[Any], TypeTag[Any])],但没有办法从 a 中获取有关每一行的编译时信息,List除非您在构建列表时构建该信息。

如果您真的想携带静态类型信息,使用隐式很容易做到这一点,只需将外部列表中的每个条目都设为特殊类。

一个简单的变体可能如下所示:

class CalculableList[A](val elements: List[A])(implicit val calc: Calculator[A]) {
  def calculate = calc(elements)
}
trait Calculator[-A] extends (List[A] => Unit)
implicit object StringCalc extends Calculator[String] {
  def apply(in: List[String]) {
    println("It's a String List")
    println(in)
  }
}
implicit object DoubleCalc extends Calculator[Double] {
  def apply(in: List[Double]) {
    println("It's a Double List")
    println(in)
  }
}

val list: List[CalculableList[_]] = List(
  new CalculableList(List(1.0, 2.0, 3.0)),
  new CalculableList(List("a", "b", "c"))
)

list foreach { _.calculate }

这种通用编程的另一种选择是使用 Miles Sabin 的Shapeless。这使用特殊的数据结构来让您构造任意大小的元组,这些元组可以被视为类型安全列表。它生成一个类似于链表的数据结构,带有一个跟踪每一行类型的通用类型包装器,因此除非您的列表相当短,否则您不会想使用它。它也有点难以学习、维护和理解——但当你理解并适当地使用它时,它会打开一些深刻的魔法。

我对您的用例知之甚少,不知道在这种情况下是否建议使用 Shapeless。

在 Scala 2.11 的 Shapeless 中,解决方案如下所示:

import shapeless._
val lists = List(1.0, 2.0, 3.0) ::
            List("a", "b", "c") ::
            HNil

object calc extends Poly1 {
  implicit def doubleList = at[List[Double]] { in =>
    println("It's a double list")
    println(in)
  }
  implicit def stringList = at[List[String]] { in =>
    println("It's a string list")
    println(in)
  }
}

lists map calc
于 2014-10-04T00:23:46.267 回答
1
    def calculateString(in:List[String]) = {
      println("It's a String List")
      println(in)
    }

    def calculateDouble(in:List[Double]){
     println("It's a Double List")
        println(in)
    }

    def castTo[T](t:T,list:List[Any]) = list.asInstanceOf[List[T]] 

   def matchAndCalculate(list:List[Any]) = list.headOption match {
        case Some(x:Double) => calculateDouble(castTo(x,list))
        case Some(x:String) => calculateString(castTo(x,list))         
        }

并检查:

scala> matchAndCalculate(List(3.4))
It's a Double List
List(3.4)

scala> matchAndCalculate(List("3.4"))
It's a String List
List(3.4)

scala> val list : List[List[Any]] = List(
     |   List(2.5, 3.6 ,7.9),
     |   List("EUR","HKD", "USD")
     | )
list: List[List[Any]] = List(List(2.5, 3.6, 7.9), List(EUR, HKD, USD))

scala> list.foreach(l=> matchAndCalculate(l))
It's a Double List
List(2.5, 3.6, 7.9)
It's a String List
List(EUR, HKD, USD)
于 2014-10-03T21:19:32.857 回答