我正在尝试创建超类实例的映射器并将其传递给父类型的集合:
def numberToString = (n:Number) => n.toString()
List(1.1, 2.1, 3.1).map(numberToString)
错误:
type mismatch; found : Number => String required: Double => ?
我很惊讶 Scala 中的 map 方法不允许超类型的函数。有更好的方法吗?
我正在尝试创建超类实例的映射器并将其传递给父类型的集合:
def numberToString = (n:Number) => n.toString()
List(1.1, 2.1, 3.1).map(numberToString)
错误:
type mismatch; found : Number => String required: Double => ?
我很惊讶 Scala 中的 map 方法不允许超类型的函数。有更好的方法吗?
Scala中没有类型Number
,所以我猜你的意思是Numeric
(Double
不是 的子类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 给出的类似视图边界表示法。
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])
允许使用超类型,除了... Number
is 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的答案。