Scala неявный выбор использования
Мне было интересно, прозрачны ли конверсии implicit
, и действительно ли лучше использовать implicits больше, um, явно. Например, предположим, что у меня есть метод, который принимает Date
как параметр, и у меня есть неявное преобразование, которое превращает a String
в Date
:
implicit def str2date(s: String) : Date = new SimpleDateFormat("yyyyMMdd").parse(s)
private def foo(d: Date)
Тогда, очевидно, я могу назвать это прозрачным преобразованием implicit
:
foo("20090910")
Было бы лучше сделать тот факт, что я преобразовываю строку в дату более явным?
class DateString(val s: String) {
def toDate : Date = new SimpleDateFormat("yyyyMMdd").parse(s)
}
implicit def str2datestr(s: String) : DateString = new DateString(s)
Итак, использование выглядит больше:
foo("20090910".toDate)
Преимущество этого заключается в том, что более понятно, что происходит. Я несколько раз поймал прозрачные преобразования implicit
, о которых я должен знать (Option
to Iterable
кто-нибудь?) и это использование все еще позволяет нам использовать преимущества implicit
s.
Ответы
Ответ 1
Я считаю, что более "явный" способ делать неявные преобразования намного лучше с точки зрения удобочитаемости, чем полностью прозрачный, по крайней мере в этом примере.
По-моему, использование implicit
полностью прозрачно от типа A
для типа B
является ОК, когда вы всегда можете просмотреть объект типа A
как способный использоваться всякий раз и объект типа B
необходимо. Например, неявное преобразование a String
в RandomAccessSeq[Char]
всегда имеет смысл - a String
всегда, концептуально, можно рассматривать как последовательность символов (в C строка - это всего лишь последовательность символов, для пример). Вызов x.foreach(println)
имеет смысл для всех String
s.
С другой стороны, более явные преобразования следует использовать, когда объект типа A
иногда может использоваться как объект типа B
. В вашем примере вызов foo("bar")
не имеет смысла и вызывает ошибку. Поскольку Scala не имеет проверенных исключений, вызов foo(s.toDate)
ясно указывает на то, что может возникнуть исключение (s
может быть недействительной датой). Кроме того, foo("bar".toDate)
явно выглядит неправильно, в то время как вам нужно проконсультироваться с документацией, чтобы узнать, почему foo("bar")
может быть неправильным. Примером этого в стандартной библиотеке Scala является преобразование из String
в Int
s через метод toInt
обертки RichString
(String
можно рассматривать как Int
s, но не все время).
Ответ 2
Когда вы делаете неявное преобразование из X в Y (например, преобразование из String в Date выше), вы, по сути, говорите, что если бы вы имели полный контроль над написанием X в первую очередь, вы бы сделали реализацию X или быть подклассом Y.
Если для X есть смысл реализовать Y, добавьте преобразование. Если это не так, то, возможно, это не подходит. Например, для String имеет смысл реализовать RandomAccessSeq [ Char], но, возможно, для String не имеет смысла реализовать Date (хотя String, реализующая StringDate, кажется прекрасным).
(Я немного опоздал, и у Флави есть отличный ответ, но я хотел добавить комментарий о том, как я думаю о implicits.)