2015-04-11 6 views

risposta

18

Ci sono due importanti differenze. In primo luogo, Option restituirà un None se il suo argomento è nullo:

scala> val x: Option[String] = Some(null) 
x: Option[String] = Some(null) 

scala> val y: Option[String] = Option(null) 
y: Option[String] = None 

Questo può essere utile, ma non è sempre quello che si vuole, e (altrettanto importante) suggerisce che c'è una ragionevole possibilità che l'argomento può essere nullo in alcuni casi, che può essere fuorviante.

Some è più appropriato per i casi in cui si desidera produrre un valore Option attorno a un valore che non è nullo. Sfortunatamente la seconda differenza è che il tipo di ritorno di Some[Whatever], , non è , che può essere davvero scomodo in alcune situazioni in cui avere Some dedotto significa che si otterranno errori di tipo quando si tenta di utilizzare None o Option in determinate posizioni in seguito. In questi casi è necessario utilizzare Some(foo): Option[Whatever], che è piuttosto spiacevole.

Ad esempio, supponiamo di avere un elenco di stringhe che rappresentano (speriamo) numeri interi e che vogliamo analizzare e sommare. Vogliamo un None se c'è un errore di analisi e un Some(total) in caso contrario. Quanto segue è un modo abbastanza ragionevole per fare questo in un unico attraversamento utilizzando la libreria standard:

List("1", "2", "3").foldLeft(Some(0)) { 
    case (acc, item) => for { 
    t <- acc 
    n <- util.Try(item.toInt).toOption 
    } yield t + n 
} 

Solo che questo non funziona, si ottiene un errore di tipo:

<console>:10: error: type mismatch; 
found : Option[Int] 
required: Some[Int] 
        t <- acc 
        ^

Siamo in grado di risolvere il problema questo scrivendo .foldLeft(Some(0): Option[Int]), ma ugh.

Questo non è un problema nell'esempio specifico perché il tipo restituito è esplicitamente Option[Int], quindi non è necessario preoccuparsi dell'inferenza di tipo. In tal caso, Some(a) è la scelta giusta.

Come nota a margine, Scalaz fornisce some e none costruttori che consentono di evitare il problema di inferenza e soluzioni rumoroso come Some(foo): Option[Whatever]:

scala> import scalaz._, Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> some(10) 
res0: Option[Int] = Some(10) 

scala> none[Int] 
res1: Option[Int] = None 

Entrambi i tipi di ritorno sono Option, che rende inferenza di tipo molto più facile. È banalmente possibile definire questi da soli se non si desidera utilizzare Scalaz:

scala> def some[A](a: A): Option[A] = Some(a) 
some: [A](a: A)Option[A] 

scala> def none[A]: Option[A] = None 
none: [A]=> Option[A] 

Se si utilizzano questi invece di Some e None non avete mai preoccuparsi di un tipo specifico di essere impropriamente dedotto.

Per riepilogare: utilizzare Option(foo) solo in situazioni in cui l'argomento può essere nullo (che idealmente dovrebbe essere solo per cose come l'interoperabilità con Java).Utilizzare Some(foo) nei casi in cui il valore è stato digitato esplicitamente come Option. Se il tipo dedotto sarà Some[Whatever], aggiungere un'annotazione di tipo : Option[Whatever] o utilizzare qualcosa come Scalaz some.

0

Per quanto mi riguarda è solo una questione di buon senso. Ovviamente puoi immaginare il caso in cui ti aspetti qualcosa del tipo Some e None non è permesso. Ma di solito il secondo modo sembra molto più naturale: il tipo di ritorno è Opzione e l'implementazione effettiva è Qualcuno (x) o Nessuno. Tecnicamente, da source code, Opzione (x) chiama apply() metodo di un oggetto associato:

object Option { 
    import scala.language.implicitConversions 
    implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList 
    def apply[A](x: A): Option[A] = if (x == null) None else Some(x) 
    def empty[A] : Option[A] = None 
} 

E Alcuni (a) chiama apply() metodo su classe caso ..

final case class Some[+A](x: A) extends Option[A] { 
    def isEmpty = false 
    def get = x 
} 

Tutti gli altri metodi sono gli stessi . Il caso d'uso con gli oggetti null è spiegato abbastanza bene nella risposta Travis Brown.

+2

Ci sono delle differenze nel loro comportamento: basta provare "Some [String] (null)" e "Option [String] (null)". –

+0

Hai perfettamente ragione sulla loro inizializzazione e hai spiegato chiaramente questo caso utente nella tua risposta! Modificherò la mia risposta per essere accurata. – ipoteka