14

我写

object MyString {
  implicit def stringToMyString(s: String) = new MyString(s)    
}

class MyString(str: String) {
  def camelize = str.split("_").map(_.capitalize).mkString

  override def toString = str
}


object Parse {
  def main(args: Array[String]) {
    val x = "active_record".camelize
    // ...
  }
}

在我的程序中。这会导致编译错误。我插入后

  import MyString.stringToMyString

然后它工作。

从 Odersky 的Programming in Scala 中,我得到源或预期目标类型的伴随对象中的隐式转换不需要导入。

4

3 回答 3

16

不需要导入源类型或预期目标类型的伴随对象中的隐式转换。

真是的。现在,该方法camelize是在 class 上定义的,实际上,在其对象伴侣内部MyString存在隐式转换。MyString但是,代码中没有任何内容告诉编译器这MyString预期的目标类型。

相反,如果你写了这个:

val x = ("active_record": MyString).camelize

那么它会起作用,因为编译器会知道您期望 "active_record"成为 a MyString,从而使其查找 object 内部的隐式转换MyString

这可能看起来有点限制,但它实际上在许多地方都有效。比如说,你有:

class Fraction(num: Int, denom: Int) {
    ...
    def +(b: Fraction) = ...
    ...
}

然后你有一个这样的代码:

val x: Fraction = ...
val y = x + 5

现在,x确实有一个+方法,其预期类型Fraction. 所以编译器会在这里寻找从IntFraction对象内部的隐式转换Fraction(并且在对象内部Int,如果有的话,因为那是源类型)。

于 2010-12-31T11:19:53.237 回答
13

在这种情况下,您需要导入,因为编译器不知道您从哪里拉出camelize方法。如果类型明确,则无需导入即可编译:

object Parse {
  def foo(s: MyString) = s.camelize

  def main(args: Array[String]) {
    val x = foo("active_record")
    println(x.toString)
  }
}

请参阅Pimp my library pattern,基于Martin 的文章

请注意,不能将 defs 放在顶层,因此您不能定义具有全局范围的隐式转换。解决办法是把def放在一个对象里面,然后导入,即

object Implicits {
    implicit def listExtensions[A](xs : List[A]) = new ListExtensions(xs)
}

然后在每个源文件的顶部,以及您的其他导入:

import Implicits._
于 2010-12-31T09:57:48.490 回答
0

我在 Scala 编程一书中尝试了 Rational 类示例,在其伴生对象中放置了一个隐式方法:

object Rational {
  implicit def intToRational(num: Int) = 
    new Rational(num)
}

但是代码

2 + new Rational(1, 2)

不起作用。为了进行转换,应用单一标识符规则,即您需要将显式方法导入范围,即使它是在伴随对象中定义的。

于 2011-04-16T06:05:08.310 回答