通用方法可转换为scala中的结构类型

时间:2011-12-07 21:17:47

标签: generics scala

为什么我不能这样做:

def compare[A <% { def toInt: Int }, 
            B <% { def toInt: Int }]
           (bs: Seq[A], is: Seq[B]): Boolean = { 
  bs.toArray.zip(is) forall { p => p._1.toInt == p._2.toInt } 
}

为了比较任何可转换为Int的类型序列?我怎样才能实现类似的模式?


更新:这应该运行Message.compare(List(1.0, 2.0, 3.0), List(0, 0, 0))

3 个答案:

答案 0 :(得分:9)

由于您正在处理Array,因此您需要ClassManifest s。

def compare[A <% { def toInt: Int } : ClassManifest, 
            B <% { def toInt: Int } : ClassManifest]
            (bs: Seq[A], is: Seq[B]): Boolean = { 
  (bs.toArray, is).zipped.forall(_.toInt == _.toInt)
}

在这种情况下编译器错误消息不能更清楚IMO。

修改

您并不需要将序列转换为数组。以下工作正常。

def compare[A <% { def toInt: Int }, 
            B <% { def toInt: Int }]
           (bs: Seq[A], is: Seq[B]): Boolean = { 
      (bs, is).zipped.forall(_.toInt == _.toInt)
}

答案 1 :(得分:2)

当我删除不必要的toArray

时,它对我来说很好
def compare[A <% { def toInt: Int }, B <% { def toInt: Int }](bs: Seq[A], is: Seq[B]): Boolean = { bs.zip(is) forall { p => p._1.toInt == p._2.toInt } }
Class A{def toInt = 4}
Class B(i: Int) {def toInt = i}
compare (List(new A, new A), List(new B(3), new B(4))) //false
compare (List(new A, new A), List(new B(4), new B(4))) //true

将Seq转换为数组需要添加一个隐式ClassManifest,但Scala不允许你将它们与视图边界混合。

答案 2 :(得分:2)

问题所在的一个很好的例子似乎是这样做:

val a = implicitly[Int => { def toInt : Int }]
a(1).toInt

Scala 2.9.1在运行时代码的某个时刻爆炸 - 我只能认为这是一个错误。

您可以使用类型类来实现您正在寻找的效果:以下代码适用于您的所有示例:

def compare[A : Numeric, B : Numeric](bs : Seq[A], cs : Seq[B]) = {
  (bs, cs).zipped.forall(implicitly[Numeric[A]].toInt(_) == implicitly[Numeric[B]].toInt(_))
}

这也应该比使用结构类型的版本更快。如果您需要添加自己的类型,应该可以转换为整数,您可以使用与https://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_9_1_final/src//library/scala/math/Numeric.scala#L1标准值相同的方式为数字类型类提供证据。