我一直在寻找这个,即使使用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
How save a TypeTag and then use it later to reattach the type to an 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 :正如Sarah指出的那样,在我将列表放入更复杂的结构之前,它可能是保持类型清单的唯一方法。
以下是挑战:是可以将List [Any]强制转换为/匹配到List [String]并作为def dummyMethod(stringList:List)等方法的输入[String])没有惹恼编译器?
答案 0 :(得分: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)
答案 1 :(得分:1)
除非您可以更改数据结构,否则Andrej的解决方案是唯一合理的方法。
您无法真正使用类型清单,因为您有两个间接级别。您需要为外部列表的每个成员使用不同的类型清单。例如,您可以拥有List[(List[Any], TypeTag[Any])]
,但是除非您在“#{1}”时获取有关每个行的编译时信息,否则无法获取该信息。 ;重新构建列表。
如果您真的想要携带静态类型信息,那么使用implicits很容易做到这一点,只需将外部列表中的每个条目都设为特殊类。
一个简单的变体可能如下所示:
List
这种通用编程的另一个选择是使用Miles Sabin的Shapeless。这使用特殊的数据结构来构建任意大小的元组,可以将其视为类型安全列表。它生成一个类似于链表的数据结构,其中包含一个通用类型包装器,用于跟踪每一行的类型,因此除非您的列表很短,否则您不会想要使用它。它也有点难以学习,维护和理解 - 但是当你理解并正确使用它时,它会开启一些深刻的魔法。
我对您的用例了解不足以了解在这种情况下Shapeless是否可行。
在Scala 2.11的Shapeless中,解决方案看起来像这样:
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 }