Scala擦除类型匹配及在不同方法中的使用

Scala擦除类型匹配及在不同方法中的使用,scala,reflection,match,manifest,erasure,Scala,Reflection,Match,Manifest,Erasure,我一直在四处搜索以实现这一点,即使使用Manifest和Reflect API,也很难实现 通过Manifest和Reflection,我可以将List[Any]匹配到一个类(List[a]),也可以通过类型T获得匹配,就像在 但我如何确定输入的类型并在方法中使用它呢 说 非常感谢 哈维 PS:正如Sarah指出的,在我创建列表时,在将其放入更复杂的结构之前,这可能是保持类型清单的唯一方法 这是一个挑战:是否可以将List[Any]强制转换为某个单词,比如List[String],并作为de

我一直在四处搜索以实现这一点,即使使用Manifest和Reflect API,也很难实现

通过Manifest和Reflection,我可以将List[Any]匹配到一个类(List[a]),也可以通过类型T获得匹配,就像在

但我如何确定输入的类型并在方法中使用它呢

非常感谢

哈维

PS:正如Sarah指出的,在我创建列表时,在将其放入更复杂的结构之前,这可能是保持类型清单的唯一方法

这是一个挑战:是否可以将List[Any]强制转换为某个单词,比如List[String],并作为def dummyMethod(stringList:List[String])等方法的输入,而不惹恼编译器?

def calculateString(in:List[String])={
println(“它是一个字符串列表”)
println(in)
}
def计算双倍(在:列表[双倍]){
println(“这是一个双重列表”)
println(in)
}
def castTo[T](T:T,list:list[Any])=list.asInstanceOf[list[T]]
def match和calculate(list:list[Any])=list.headOption匹配{
case-Some(x:Double)=>calculateDouble(castTo(x,list))
case-Some(x:String)=>calculateString(castTo(x,list))
}
并检查:

scala>匹配与计算(列表(3.4))
这是一份双重清单
清单(3.4)
scala>matchAndCalculate(列表(“3.4”))
这是一个字符串列表
清单(3.4)
scala>val list:list[list[Any]]=list(
|清单(2.5、3.6、7.9),
|清单(“欧元”、“港币”、“美元”)
| )
清单:清单[清单[任何]]=清单(清单(2.5、3.6、7.9)、清单(欧元、港币、美元))
scala>list.foreach(l=>matchAndCalculate(l))
这是一份双重清单
清单(2.5、3.6、7.9)
这是一个字符串列表
清单(欧元、港币、美元)

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

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

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

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

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 }
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
这种泛型编程的另一个选择是使用Miles Sabin的。它使用特殊的数据结构来构造任意大小的元组,这些元组可以被视为类型安全列表。它生成一个类似于链表的数据结构,带有一个通用类型包装器,可以跟踪每一行的类型,因此除非列表很短,否则您不想使用它。学习、维护和理解它也有点困难,但当你理解并恰当地使用它时,它会开启一些深层次的魔法

我对您的用例了解不够,不知道在这种情况下,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 }
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

嗨,Andrej,我认为这行不通,因为calculateLong()将要求列表的类型[Long]。我试过了,并在帖子中更新了我的代码。如果i.headOption.exist(u.isInstanceOf[Long])=>calculateLong(i)^这是正确的解决方案,您只需要强制转换列表即可。list.headOption match{case Some(l:Long)=>calculateLong(l.asInstanceOf[list[Long]])嗨,Sarah和Andrzej,不是真的,您看到的主要困难是输入是list[Any],输入的类型已经丢失。以下内容不适用于asInstanceOf不能回退:val列表:列表[列表[任何]]=列表(列表(2.5,3.6,7.9),列表(“欧元”、“港币”、“美元”);在您的代码中将行
list.foreach(l=>matchAndCalculate(l))更改为
list.foreach(l=>matchAndCalculate(l))
list.foreach(l=>matchAndCalculate(l))
您是对的,这可能是在将列表放入更复杂的结构之前,在第一行创建列表时保持类型清单的唯一方法。但我不确定您的代码是否可以工作,因为您在这里定义了val list:list[CalculableList[Any]],编译器将查找CalculableList[Any]。我得到错误:类型不匹配;发现:CalculableList[Double]必需:CalculableList[Any]注意:Double您是对的:缺少一些方差注释。我对我的答案进行干编码,只是为了展示解决方案的大致情况。你似乎有足够的知识来填补任何空白。我将根据您的评论进行编辑。顺便说一句,这类事情的另一个选择是使用Shapess,这是一个令人印象深刻的工具包,用于对这类事情进行抽象。如果外部列表很长,它可能会有太多的开销,但是如果您只处理几行,它可能会工作得很好。