Poderia/deve/deve uma conversão implícita de t para opção [t] ser adicionada/criada em scala?

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

  •  20-09-2019
  •  | 
  •  

Pergunta

Esta é uma oportunidade de tornar as coisas um pouco mais eficientes (para o PRORMAMM): acho que fica um pouco cansativo tendo que envolver as coisas Some, por exemplo Some(5). Que tal algo assim:

implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
Foi útil?

Solução

Você perderia algum tipo de segurança e possivelmente causaria confusão. Por exemplo:

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

Eu (por qualquer motivo) pensei que tinha uma lista, e ela não foi pega pelo compilador quando o itenei porque foi convertido automaticamente em uma opção [int].

Devo acrescentar que acho que isso é um ótimo implícito por ter explicitamente importado, provavelmente não é uma inadimplência global.

Outras dicas

Observe que você pode usar o explícito implícito padrão que evitaria confusão e manteria o código conciso ao mesmo tempo.

O que quero dizer com implícito explícito é, em vez de ter uma conversão direta de T para Option[T] Você pode ter uma conversão para um objeto de invólucro que fornece os meios para fazer a conversão de T para 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)

... eu posso encontrar um nome melhor para isso do que Optionable, mas agora você pode escrever código como:

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

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

Acredito que dessa maneira é totalmente transparente e ajuda na compreensão do código escrito - eliminando todos os cheques para nulos de uma maneira agradável.

Note o T <: AnyRef - Você só deve fazer essa conversão implícita para tipos que permitem null valores, que por definição são tipos de referência.

As diretrizes gerais para conversões implícitas são as seguintes:

  • Quando você precisa adicionar membros a um tipo (a la "aulas abertas"; também conhecido novo tipo que se estende AnyRef e que define apenas os membros que você precisa.
  • Quando você precisa "corrigir" uma hierarquia de herança. Assim, você tem algum tipo A que deveria subclassificado B, mas não por algum motivo. Nesse caso, você pode definir uma conversão implícita de A para B.

Estes são os casos em que é apropriado definir uma conversão implícita. Qualquer outra conversão é executada em problemas de segurança e correção com pressa.

Realmente não faz sentido para T para estender Option[T], e obviamente, o objetivo da conversão não é simplesmente a adição de membros. Assim, essa conversão seria inadvisível.

Parece que isso pode ser confuso para outros desenvolvedores, enquanto eles lêem seu código.

Geralmente, ao que parece, implicit Trabalha para ajudar Some Então isso parece ser incômodo.

Você pode querer colocar algum código mostrando que ele era usado, para ver como seria confuso.

Você também pode tentar sobrecarregar o método:

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
}

Isso me parece bom, exceto que pode não funcionar para um T primitivo (que não pode ser nulo). Eu acho que um genérico não especializado sempre recebe primitivas em caixa, então provavelmente está tudo bem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top