为什么隐式转换在列表中不起作用?

时间:2011-07-18 06:13:56

标签: scala implicit-conversion

有人可以快速解释为什么隐式转换在这些情况下不起作用?感谢。

scala> implicit def strTwoInt (s: String):Int = s.toCharArray.map{_.asDigit}.sum
strTwoInt: (s: String)Int

scala> List[Int]("1","2","3") sum
res3: Int = 6

scala> List("1","2","3") sum
<console>:9: error: could not find implicit value for parameter num: Numeric[java.lang.String]
        List("1","2","3") sum

scala> val a = List("1","2","3")                          
scala> a.foldLeft(0)((i:Int, j:Int) => i+j)
<console>:10: error: type mismatch;
 found   : (Int, Int) => Int
 required: (Int, java.lang.String) => Int

2 个答案:

答案 0 :(得分:7)

您的隐式转换会转换Int中的String。在您的第一个示例中,它是由您尝试将字符串放入Ints列表的事实触发的。

在第二个示例中,您有一个String of List,并且您调用方法sum,它采用隐式Numeric[String]。您的转换不适用,因为您既没有尝试在编译器期望Int的地方传递String,也没有尝试调用Int中定义的方法而不是String中定义的方法。在这种情况下,您可以定义使用显式转换的Numeric[String],或者使用以List[Int]作为参数的方法(给编译器提示):< / p>

scala> def sumIt( xs: List[Int] ) = xs sum
sumIt: (xs: List[Int])Int

scala> sumIt( List("1","2","3") )
res5: Int = 6

在第三个示例中,foldLeft第二个参数必须是类型:

(Int,String) => Int

您实际传递的是类型:

(Int,Int) => Int

但是,您没有定义这两种类型之间的任何隐式转换。但是:

a.foldLeft(0)((i:Int, j:String) => i+j)

触发您的转化并发挥作用。

修改:以下是实施Numeric[String]

的方法
implicit object StringNumeric extends math.Numeric[String] {
  val num = math.Numeric.IntIsIntegral
  def plus(x: String, y: String) = num.plus(x,y).toString
  def minus(x: String, y: String) = num.minus(x,y).toString
  def times(x: String, y: String) = num.times(x,y).toString
  def negate(x: String): String = num.negate(x).toString
  def fromInt(x: Int) = x.toString
  def toInt(x: String) = x
  def toLong(x: String) = toInt(x)
  def toFloat(x: String) = toInt(x)
  def toDouble(x: String) = toInt(x)
  def compare(x:String,y:String) = num.compare(x,y)
}

scala> List("1","2","3") sum
res1: java.lang.String = 6

它有效,但结果是一个字符串。

答案 1 :(得分:4)

以下是一个快速解释:隐式转换适用于直接转换的类型(例如,在您的情况下为StringInt),而不适用于任何参数化类型T[String]T[Int] - 除非为T本身定义了隐式转换,否则列表不是这样。

您的隐式转换不适用于您的两种情况(即使您从List[String]隐式转换为List[Int],也不适用)。只有当您需要Int类型的值并且您正在传递String时,它才会自动应用。这里,在第一种情况下,方法sum要求Numeric[String]隐式参数 - 从StringInt的隐式转换不会在这里发挥作用。

下次尝试的类似问题:集合中的foldLeft需要(Int, String) => Int类型的函数。想象一下,如果基于从StringInt的隐式转换,编译器会自动提供从(Int, Int) => Int(Int, String) => Int的隐式转换......

对于所有这些情况,解决此问题的简便方法是事先在您的收藏中明确调用.map(stringToInt)