【问题标题】:Why implicit conversion doesn't work in Lists?为什么隐式转换在列表中不起作用?
【发布时间】:2011-07-18 06:13:56
【问题描述】:

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

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

【问题讨论】:

  • 你能不能更具体一点,在你的隐式转换中你想做什么sumList[Int]("1","2","3")之后的sum
  • @Lutz 你是指def sum [B &gt;: A] (implicit num: Numeric[B]): B 形式的sum?也许吧,但我不明白它是如何工作的
  • 抱歉不够清楚。您的示例的预期结果是什么?

标签: scala implicit-conversion


【解决方案1】:

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

在您的第二个示例中,您有一个字符串列表并调用方法 sum,该方法采用隐式 Numeric[String]。您的转换不适用,因为您既没有尝试在编译器期望 Int 的地方传递字符串,也没有尝试调用在 Int 中而不是在 String 中定义的方法。在这种情况下,您可以定义一个Numeric[String],它明确使用您的转换,或者使用一个将List[Int] 作为参数的方法(向编译器提供提示):

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

它可以工作,但结果是一个字符串。

【讨论】:

  • 就像a.foldLeft(0)(_ + _)...您认为您可以扩展定义 Numeric[String] 所涉及的内容吗?
【解决方案2】:

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

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

下一次尝试的类似问题:集合中的foldLeft 需要(Int, String) =&gt; Int 类型的函数。想象一下,如果基于从StringInt 的隐式转换,编译器自动提供从(Int, Int) =&gt; Int(Int, String) =&gt; Int 的隐式转换,我们会陷入混乱……

对于所有这些情况,解决此问题的简单方法是事先在您的集合上显式调用 .map(stringToInt)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-11
    相关资源
    最近更新 更多