Вопрос

Мне было интересно, действительно ли прозрачные неявные преобразования являются такой хорошей идеей, и может ли лучше на самом деле лучше использовать имплицит больше, например, явно . Например, предположим, у меня есть метод, который принимает 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, выглядит неплохо).

(Я немного опоздал, и у Флавиу отличный ответ, но я хотел добавить комментарий о том, как я думаю о последствиях.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top