1

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

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

错误:

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

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

4

3 回答 3

2

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

Numeric如果是这样,您可以通过将函数的参数指定为上下文绑定来实现您想要的numberToString(即指定必须有从参数类型到的范围内隐式转换Numeric,这对于 , 等通常是Int正确Double的):

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 世界中。如果您确实打算将参数限制为numberToString类型java.lang.Number而不是scala.math.Numeric,则使用@wingedsubmariner 给出的类似视图边界表示法。

于 2013-10-29T12:58:45.530 回答
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])
于 2013-10-29T13:05:23.970 回答
0

允许使用超类型,除了... Numberis java.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这里使用,但我想这只是你的问题的简化版本。

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

于 2013-10-29T13:00:29.107 回答