Неявное преобразование, импорт требуется или нет? - PullRequest
14 голосов
/ 31 декабря 2010

пишу

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

Тогда это работает.

Из программирования Одерского в Scala Я получил, что неявное преобразование в сопутствующем объекте исходного или ожидаемого целевых типов не нужно импортировать.

Ответы [ 3 ]

16 голосов
/ 31 декабря 2010

неявное преобразование в компаньоне объект источника или ожидаемый целевые типы не должны быть импортирован.

Достаточно верно. Теперь метод camelize определен в классе MyString, и, действительно, в его объектном компаньоне происходит неявное преобразование в MyString. Однако в коде нет ничего, сообщающего компилятору, что MyString является ожидаемым типом цели.

Если вместо этого вы написали это:

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

тогда это будет работать, потому что компилятор будет знать, что вы ожидаете, что "active_record" будет MyString, что заставляет его искать неявное преобразование внутри объекта MyString.

Это может выглядеть немного ограничительно, но на самом деле это работает во многих местах. Скажем, например, у вас было:

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

А потом у вас был такой код:

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

Теперь у x есть метод +, для которого ожидаемый тип равен Fraction. Таким образом, здесь компилятор будет искать неявное преобразование из Int в Fraction внутри объекта Fraction (и внутри объекта Int, если он был, поскольку это тип источника).

13 голосов
/ 31 декабря 2010

В этой ситуации вам нужен импорт, потому что компилятор не знает, откуда вы извлекли метод 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 , основанный на статье Мартина :

Обратите внимание, что невозможно поместить def на верхний уровень, поэтому вы не можете определить неявное преобразование с глобальной областью действия. Решение состоит в том, чтобы поместить def внутри объекта, а затем импортировать его, т.е.

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

И затем в верхней части каждого исходного файла вместе с другими вашими импортами:

import Implicits._
0 голосов
/ 16 апреля 2011

Я попробовал пример класса Rational в книге «Программирование в Scala», поместил неявный метод в сопутствующий объект:

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

, но код

2 + new Rational(1, 2)

не работает.Для выполнения преобразования применяется правило единого идентификатора, т. Е. Вам необходимо импортировать явный метод в область действия, даже если он определен в сопутствующем объекте.

...