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

StackOverflow https://stackoverflow.com/questions/1746359

  •  20-09-2019
  •  | 
  •  

Вопрос

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

implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
Это было полезно?

Решение

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

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

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

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

Другие советы

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

Под явным неявным я подразумеваю, а не прямое преобразование из 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

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

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

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

  • Когда вам нужно добавить элементы в тип (а-ля «открытые классы»;также известный как шаблон «Прокачай мою библиотеку»), преобразовать в новый тип, который расширяет AnyRef и который определяет только тех членов, которые вам нужны.
  • Когда вам нужно «исправить» иерархию наследования.Таким образом, у вас есть некоторый тип A который должен иметь подкласс B, но по какой-то причине этого не сделал.В этом случае вы можете определить неявное преобразование из A к B.

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

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

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

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

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

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

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
}

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

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