Подтвердить что ты не робот

Может ли/неявное преобразование из T в Option [T] быть добавлено/создано в Scala?

Является ли это возможностью сделать вещи немного более эффективными (для прорамера): мне кажется, что немного утомительно обернуть вещи в Some, например. Some(5). Что-то вроде этого:

implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
4b9b3361

Ответ 1

Вы потеряете некоторую безопасность и, возможно, будете путаться. Например:

  val iThinkThisIsAList = 2 
  for (i <- iThinkThisIsAList) yield { i + 1 }

Я (по какой-то причине) думал, что у меня есть список, и он не попал в компилятор, когда я его повторил, потому что он был автоматически преобразован в Option [Int].

Я должен добавить, что я думаю, что это очень неявное, чтобы явно импортировать, возможно, не глобальное значение по умолчанию.

Ответ 2

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

То, что я подразумеваю под явным неявным, а не с прямым преобразованием из T в Option[T], вы могли бы преобразовать в объект-оболочку, который предоставляет средства для преобразования из T в Option[T].

class Optionable[T <: AnyRef](value: T) {
  def toOption: Option[T] = if ( value == null ) None else Some(value)
}

implicit def anyRefToOptionable[T <: AnyRef](value: T) = new Optionable(value)

... Я мог бы найти лучшее имя для него, чем Optionable, но теперь вы можете написать код вроде:

val x: String = "foo"
x.toOption // Some("foo")

val y: String = null
x.toOption // None

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

Обратите внимание на T <: AnyRef - вы должны сделать это неявное преобразование для типов, которые позволяют значения null, которые по определению являются ссылочными типами.

Ответ 3

Общие рекомендации для неявных преобразований следующие:

  • Когда вам нужно добавить участников к типу (a la "open classes", aka "шаблон pimp my library" ), преобразуйте его в новый тип, который расширяет AnyRef и который определяет только тех членов, которые вам нужны.
  • Когда вам нужно "исправить" иерархию наследования. Таким образом, у вас есть некоторый тип A, который должен иметь подклассу B, но по какой-то причине не был. В этом случае вы можете определить неявное преобразование от A до B.

Это единственные случаи, когда целесообразно определить неявное преобразование. Любое другое преобразование спешит на проблемы безопасности и корректности типов в спешке.

Для T действительно не имеет смысла расширять Option[T], и, очевидно, цель преобразования - это не просто добавление членов. Таким образом, такое преобразование было бы нецелесообразным.

Ответ 4

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

Как правило, кажется, что implicit работает, чтобы помочь сбрасывать из одного объекта в другой, вырезать запутанный код литья, который может загромождать код, но, если у меня есть переменная, и она каким-то образом становится Some, то это будет кажется, надоедает.

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

Ответ 5

Вы также можете попробовать перегрузить метод:

def having(key:String) = having(key, None)

def having(key:String, default:String) = having(key, Some(default))

def having(key: String, default: Option[String]=Option.empty) : Create = {
  keys += ( (key, default) )
  this
}

Ответ 6

Это выглядит хорошо для меня, за исключением того, что он не может работать для примитива T (который не может быть null). Я предполагаю, что неспециализированный родословный всегда получает примитивы в коробке, поэтому, вероятно, это хорошо.