2014-06-17 23 views
5

Quindi, un Option[Int] o Option[String] o per quella materia Option[A] risultati in Some(A) o None, ma un Boolean è diverso in quanto rappresenta intrinsecamente stati duali (true/false), lo fa senso avere Option[Boolean]? Lo affronto spesso quando una risposta JSON non deve includere il campo booleano basato su determinate logiche di business.Scala: l'opzione [Booleano] ha senso?

Qualche idea?

+4

Certo, è una rappresentazione ragionevole per un tri-stato: True, False, Don't-Know/Don't-Care. –

+1

forse non prestazioni ottimali (perché è una classe in piena regola), ma perché no? se è necessario ottimizzare, è possibile codificarlo come Byte o Int, ad esempio –

risposta

7

L'opzione è una preoccupazione ortogonale per il tipo di dati. Quindi sì, Option[Boolean] ha esattamente lo stesso significato di Option[Int].

Parliamo del tuo caso d'uso particolare.


Se la regola di business dice il campo (diciamo) isPrimeTime deve essere di tipo Boolean, ma è opzionale, allora si dovrebbe modellare con un Option[Boolean].

None in questo contesto indica assenza del valore, Some(true) significherebbe "presenti e vero", Some(false) significherebbe "presente e falso". Ciò consentirebbe anche di aggiungere le impostazioni predefinite nel codice come illustrato di seguito:

val isPrimeTime = json.getAs[Option[Boolean]]("isPrimeTime").getOrElse(false) 

si possono impiegare vari Option combinatori per altri casi di uso comune che si presentano in tali impostazioni. (Avrei lasciate che il vostro lavoro immaginazione su quello.)


Se il dominio ha un sacco di questi campi "tre stati", e se il terzo stato indica alcuni specifici domini idea, qualcosa che non evidente dal contesto, Consiglio vivamente di creare il proprio tipo di somma. Anche se tecnicamente puoi ancora usare Option[Boolean], questo potrebbe non essere buono per la tua sanità mentale. Ecco un esempio.

sealed trait SignalValueIndication 
case class Specified(value: Boolean) extends SignalValueIndication 
case object DontCare extends SignalValueIndication 

// Use 
val signalValue = signalValueIndication match { 
    case Specified(value) => value 
    case DontCare => chooseOptimalSignalValueForImpl 
} 

Questo sembrerebbe come questo sarebbe un enorme spreco, dal momento che si sta perdendo i combinatori disponibili su Option. Questo è in parte giusto. In parte perché poiché i due tipi sono isomorfi, scrivere ponti non sarebbe così difficile.

sealed trait SignalValueIndication { 
    // ... 
    def toOption: Option[Boolean] = this match { 
    case Specified(value) => Some(value) 
    case DontCare => None 
    } 

    def getOrElse(fallback: => Boolean) = this.toOption.getOrElse(fallback) 
} 

object SignalValueIndication { 
    def fromOption(value: Option[Boolean]): SignalValueIndication = { 
    value.map(Specified).getOrElse(DontCare) 
    } 
} 

Questo è ancora significativa la duplicazione, e si deve giudicare caso per caso se la chiarezza aggiunto costituisce per essa.

Un consiglio simile è stato fatto da HaskellTips su twitter di recente, e ne è seguita una discussione simile. Lo puoi trovare here.


A volte la presenza o l'assenza di un campo è una decisione che è possibile codificare nella struttura dei dati. Usare Option sarebbe sbagliato in questi casi.

Ecco un esempio. Immagina che ci sia un campo differentiator per il quale sono consentiti i seguenti due tipi di valori.

// #1 
{ "type": "lov", "value": "somethingFromSomeFixedSet" }, 

// #2 
{ "type": "text", "value": "foo", "translatable": false } 

Qui, assumere il campo translatable è obbligatorio, ma solo per ` "tipo": "text".

Si potrebbe modellare con Option così:

case class Differentiator(
    _type: DifferentiatorType, 
    value: String, 
    translatable: Option[Boolean] 
) 

Tuttavia un modo migliore per modello che potrebbe essere: Effective ML discorso di

sealed trait Differentiator 
case class Lov(value: String) extends Differentiator 
case class Text(value: String, translatable: Boolean) extends Differentiator 

Yaron Minsky ha una sezione su questo. Potresti trovarlo utile. (Anche se usa ML per illustrare i punti, il discorso è abbastanza accessibile e applicabile anche ai programmatori di Scala).

10

Questo è un uso corretto di Option[Boolean]. Supponiamo che abbia un lavoro in esecuzione che richiederà un po 'di tempo per essere completato, e voglio che un valore rappresenti se il lavoro è stato un successo o meno. Ciò suggerisce un valore di tipo Option[Boolean].

  • Fino a quando il lavoro è finito, non so se ha successo o meno, quindi ha valore None.
  • Quando il lavoro è terminato, è stato un successo o non lo era, quindi ha il valore Some(true) o Some(false).
+0

Kudos se si può dare un esempio per "Option [Option [Boolean]]'. –

+1

Per ogni 'X', potresti voler usare' Opzione [X] 'per indicare se' X' è disponibile. Supponiamo, per esempio, di avere una sottoattività per verificare se un lavoro è un successo; quella sottotabella riporta un 'Opzione [Booleano]' per indicare successo/fallimento/incompleto, e si potrebbe restituire un 'Opzione [Opzione [Booleano]]' per indicare che l'attività secondaria non risponde. Alla fine è possibile appiattirlo, ma inizialmente si desidera rispondere in modo molto diverso a un errore dell'attività e un failover del gestore attività. –

+0

@RexKerr Intendevo che fosse divertente. :) Ma una buona spiegazione comunque. –

Problemi correlati