Scala定义了超类的映射器

时间:2013-10-29 12:46:04

标签: scala scala-collections

我正在尝试创建超类实例的映射器并将其传递给父类型的集合:

def numberToString =  (n:Number) => n.toString()
List(1.1, 2.1, 3.1).map(numberToString)

错误:

type mismatch; found : Number => String required: Double => ?

我很惊讶Scala中的map方法不允许超类型的函数。有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

Scala中没有Number类型,所以我猜你的意思是NumericDouble不是Numeric的子类,但它可以是通过隐式转换强制转换为Numeric

如果是这样,您可以通过将Numeric指定为numberToString函数的参数的上下文绑定来实现您想要的目标(即,指定必须存在范围内的隐式转换)参数类型为Numeric,通常适用于IntDouble等):

scala> def numberToString[N : Numeric] =  (n: N) => n.toString()
numberToString: [N](implicit evidence$1: Numeric[N])N => String

scala> List(1.1, 2.1, 3.1).map(numberToString2)
res2: List[String] = List(1.1, 2.1, 3.1)

修改

请注意,我假设您希望尽可能多地保留Scala世界。如果您打算将参数限制为numberToStringjava.lang.Number类型而不是scala.math.Numeric,那么请使用@wingedsubmariner给出的类似视图边界符号。

答案 1 :(得分:1)

Scala允许您将接受超类型的函数传递给map。这实际上是通过向上转换序列来实现的,而不是按原样接受函数:

def intSeqToInt(x: Seq[Int]) = x.length
List(List(1), List(2)).map(intSeqToInt)
res2: List[Int] = List(1, 1)

List [List [Int]]被强制转换为List [Seq [Int]],然后其map具有intSeqToInt的正确类型。

你的问题是Double不是Number的子类。 Number是指java.lang.Number,Double是scala.Double,它只是AnyVal的一个子类。存在从Double到Number的隐式转换,但在这种情况下,您必须使用视图绑定专门请求它:

def numberToString[N <% Number](n:N) = n.toString()
List(1.1, 2.1, 3.1).map(numberToString[Double])

答案 2 :(得分:0)

允许使用超级类型,但... Numberjava.lang.Number,不是scala.Double的超级类型。

具有实际超类型的示例:

scala> def numberToString =  (n:AnyVal) => n.toString()
numberToString: AnyVal => String

scala> List(1.1, 2.1, 3.1).map(numberToString)
res0: List[String] = List(1.1, 2.1, 3.1)

显然你可以在这里使用_.toString,但我想这只是你问题的简化版本。

编辑:在数值的特殊情况下,正确的方法是在@ Shadowlands的答案中使用Numeric