質問

I'm trying to create a mapper of the superclass instance and pass it to a collection of the parent type:

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

Error:

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

I'm surprised that the map method in Scala doesn't allow functions of a super type. Is there a better way how to do it?

役に立ちましたか?

解決

There is no type Number in Scala, so I am guessing you are meaning Numeric (Double is not a sub-class of Numeric, but it can be coerced to Numeric via implicit conversion).

If so, you can achieve what you want by specifying Numeric as a context bound for the parameter of the numberToString function (ie. specify that there must be an in-scope implicit conversion from the argument type to Numeric, which will generally be true for Int, Double, etc):

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)

EDIT

Note that I am assuming here that you want to stay as much as possible in the Scala world. If you do intend restricting the argument to numberToString to the java.lang.Number type rather than scala.math.Numeric, then use the similar view bounds notation as given by @wingedsubmariner.

他のヒント

Scala does allow you to pass a function that accepts a super type to map. This actually works by upcasting the sequence, not by accepting the function as is:

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

List[List[Int]] is cast to List[Seq[Int]], and then its map has the proper type for intSeqToInt.

Your problem is that Double is not a subclass of Number. Number refers to java.lang.Number, Double is scala.Double, which is only a subclass of AnyVal. There is an implicit conversion from Double to Number, but in this instance you have to specifically ask for it with a view bound:

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

Using a super type is allowed, except that... Number is java.lang.Number, which is not a super type of scala.Double.

An example with an actual super type:

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)

Obviously you could just use _.toString here, but I suppose this is just a simplified version of your problem.

Edit: in the special case of numeric values, the proper way would be to use Numeric as in @Shadowlands's answer.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top