Scala неявный выбор использования
Вопрос
Мне было интересно, действительно ли прозрачные неявные
преобразования являются такой хорошей идеей, и может ли лучше на самом деле лучше использовать имплицит больше, например, явно . Например, предположим, у меня есть метод, который принимает Date
в качестве параметра, и у меня есть неявное преобразование, которое превращает String
в Date
: р>
implicit def str2date(s: String) : Date = new SimpleDateFormat("yyyyMMdd").parse(s)
private def foo(d: Date)
Тогда, очевидно, я могу назвать это прозрачным неявным
преобразованием:
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)
Преимущество этого состоит в том, что позже становится яснее, что происходит - меня уже несколько раз ловили прозрачные неявные
преобразования, о которых я должен знать ( Option
to Iterable
кому-нибудь?), и это использование все еще позволяет нам использовать возможности неявных
s.
Решение
Я считаю, что более "явный" способ неявного преобразования намного лучше с точки зрения читабельности, чем полностью прозрачный, по крайней мере, в этом примере. Р>
По моему мнению, использование неявных
полностью прозрачно от типа A
до типа B
нормально, когда вы можете всегда рассматриваем объект типа A
как пригодный для использования всякий раз, когда необходим объект типа B
. Например, неявное преобразование String
в RandomAccessSeq [Char]
всегда имеет смысл - 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
, но не все время ).
Другие советы
Когда вы делаете неявное преобразование из X в Y (например, преобразование из String в Date выше), вы, по сути, говорите, что, если бы у вас был полный контроль над написанием X, вы бы заставили X реализовать или быть подклассом Y.
Если для X имеет смысл реализовать Y, добавьте преобразование. Если это не так, то, возможно, это не подходит. Например, для String имеет смысл реализовывать RandomAccessSeq [Char], но, возможно, для String не имеет смысла реализовывать Date (хотя String, реализующий StringDate, выглядит неплохо).
(Я немного опоздал, и у Флавиу отличный ответ, но я хотел добавить комментарий о том, как я думаю о последствиях.)