Scala неявный выбор использования

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

2 ответа

Решение

Я считаю, что более "явный" способ выполнения неявных преобразований намного лучше с точки зрения читабельности, чем полностью прозрачный, по крайней мере, в этом примере.

На мой взгляд, используя implicitполностью прозрачно от типа A печатать B хорошо, когда вы всегда можете просмотреть объект типа A как возможность быть использованным всякий раз, когда и объект типа B нужно. Например, неявное преобразование String к RandomAccessSeq[Char] всегда имеет смысл - String концептуально всегда можно рассматривать как последовательность символов (например, в C строка - это просто последовательность символов). Вызов x.foreach(println) имеет смысл для всех Strings.

С другой стороны, более явные преобразования должны использоваться, когда объект типа A иногда может использоваться как объект типа B, В вашем примере вызов foo("bar") не имеет смысла и выдает ошибку. Поскольку у Scala нет проверенных исключений, вызов foo(s.toDate) четко сигнализирует, что может быть выброшено исключение (s может не быть действительной датой). Также, foo("bar".toDate) выглядит неправильно, в то время как вам нужно ознакомиться с документацией, чтобы понять, почему foo("bar") может быть не так. Примером этого в стандартной библиотеке Scala являются преобразования из Stringс Intс помощью toInt метод RichString обертка (Stringс можно рассматривать как Intс, но не все время).

Когда вы делаете неявное преобразование из X в Y (например, преобразование из String в Date выше), вы, по сути, говорите, что, если бы у вас был полный контроль над написанием X в первую очередь, вы бы заставили X реализовать или быть подкласс Y.

Если для X имеет смысл реализовать Y, добавьте преобразование. Если это не так, то, возможно, это не подходит. Например, для String имеет смысл реализовывать RandomAccessSeq[Char], но, возможно, для String не имеет смысла реализовывать Date (хотя String, реализующий StringDate, выглядит неплохо).

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

Другие вопросы по тегам