Potrebbe / dovrebbe una conversione implicita da T a Opzione [T] essere aggiunto / creato a Scala?

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

  •  20-09-2019
  •  | 
  •  

Domanda

Si tratta di un'opportunità per rendere le cose un po 'più efficiente (per il prorammer): Trovo diventa un po' stancante dover avvolgere le cose in Some, per esempio Some(5). Che dire qualcosa di simile:

implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
È stato utile?

Soluzione

Si potrebbe perdere un po 'di sicurezza tipo e causare confusione. Ad esempio:

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

I (per qualsiasi motivo) pensavo di avere una lista, e non ha ottenuto catturati dal compilatore quando mi ripetuti su perché era auto-convertita in un'opzione [Int].

Vorrei aggiungere che credo che questo sia un grande implicita di aver esplicitamente importato, solo probabilmente non un default globale.

Altri suggerimenti

Si noti che è possibile utilizzare il esplicito modello implicita che sarebbe evitare confusione e mantenere il codice stringato, allo stesso tempo.

Quello che voglio dire è esplicita implicita piuttosto che avere una conversione diretta da T a Option[T] si potrebbe avere una conversione a un oggetto wrapper che fornisce i mezzi per fare la conversione da T a 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)

... potrei trovare un nome migliore per esso che Optionable, ma ora è possibile scrivere codice come:

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

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

Credo che in questo modo è completamente trasparente ed aiuta nella comprensione del codice scritto -. Eliminando tutti i controlli per nulla in un modo carino

Si noti la T <: AnyRef -. Si dovrebbe fare solo conversione implicita per i tipi che consentono valori null, che per definizione sono i tipi di riferimento

Le linee guida generali per le conversioni implicite sono i seguenti:

  • Quando è necessario aggiungere membri ad un tipo (a la "classi aperte", alias il pattern "pimp my library"), convertire in un nuovo tipo di , che si estende AnyRef e che definisce solo la membri è necessario.
  • Quando è necessario una gerarchia di ereditarietà "corretto". Pertanto, è necessario un certo tipo A che dovrebbe avere B sottoclasse, ma non l'ha fatto per qualche motivo. In tal caso, è possibile definire una conversione implicita da A a B.

I seguenti sono i solo casi in cui è opportuno definire una conversione implicita. Qualsiasi altra conversione si imbatte in problemi di sicurezza e correttezza tipo di fretta.

In realtà non ha alcun senso per T di estendere Option[T], e, ovviamente, lo scopo della conversione non è semplicemente l'aggiunta di membri. Così, una tale conversione sarebbe sconsigliabile.

Sembrerebbe che questo potrebbe essere fonte di confusione per altri sviluppatori, mentre leggono il vostro codice.

In generale, a quanto pare, implicit lavora per aiutare getto da un oggetto ad un altro, per tagliare fuori il codice di colata di confusione che può ingombrare il codice, ma, se ho qualche variabile e diventa in qualche modo un Some allora che sembrerebbe essere fastidioso .

Si consiglia di mettere un po 'di codice che mostra è in uso, per vedere come fonte di confusione sarebbe stato.

Si potrebbe anche provare a sovraccaricare il metodo:

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
}

Che sembra buono con me, tranne che non può funzionare per una T primitivo (che non può essere nullo). Credo che un non-specializzati generici primitive sempre viene in scatola, quindi probabilmente va bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top