2011-04-26 17 views

Respuesta

45

Debe usar Option(null) para alcanzar el efecto deseado y devolver None.

Some(null) simplemente crea un nuevo Option con un valor definido (de ahí Some), que es en realidad null, y hay pocas razones válidas para crear nunca uno como éste en el código real.

+0

Esto no explica mucho ... ¿Podría ser más explícito? –

+1

@Mauricio Daniel tiene un buen ejemplo de por qué 'Some (null)' no debe transformarse en 'None'. –

25

Desafortunadamente, null es un valor válido para cualquier tipo de AnyRef, una consecuencia de la interoperabilidad de Scala con Java. Entonces, un método que toma un objeto de tipo A y, internamente, lo almacena dentro de un Option, bien podría necesitar almacenar un null dentro de esa opción.

Por ejemplo, supongamos que tiene un método que toma el encabezado de una lista, comprueba si esa cabecera corresponde a una clave en una tienda, y luego devuelve verdadero si lo es. Se podría aplicar de esta manera:

def isFirstAcceptable(list: List[String], keys: Set[String]): Boolean = 
    list.headOption map keys getOrElse false 

lo tanto, aquí está la cosa ... si el que en el interior listkeys y venir de alguna API de Java, que tanto bien puede contener null! Si Some(null) no fue posible, entonces isFirstAcceptable(List[String](null), Set[String](null)) devolvería false en lugar de true.

+2

+1 Bonito caso de uso de por qué 'Some (null)' debería existir! –

2

Como un simple experimento mental, considere dos listas de cadenas, una de longitud 5 y uno de longitud 20.

Debido a que estamos ejecuta en la JVM, es posible insertar null como un elemento válido en uno de estas listas, así que colóquelo en la lista larga como elemento # 10

¿Cuál es, entonces, la diferencia entre los valores devueltos por las dos expresiones siguientes?

EDIT: intercambiada get para lift, yo estaba pensando en los mapas ...

shortList.lift(10) //this element doesn't exist 
longList.lift(10) //this element exists, and contains null 
+0

Lo anterior arroja IndexOutOfBoundsException – Synesso

+0

@Synesso - 'shortList (10)' lanzará una excepción, verdadero. Pero eso no es lo que estoy haciendo ... –

+0

Disculpas, supuse que hablabas de java.util.List ya que tu argumento parecía similar al mío. ¡Asumí demasiado! – Synesso

11

Gran parte de WTFs de Scala se puede atribuir a su necesidad de compatibilidad con Java. null se usa a menudo en Java como un valor, lo que indica, tal vez la ausencia de un valor. Por ejemplo, hashMap.get(key) devolverá null si la clave no coincide.

Con esto en mente, considere los siguientes valores posibles de envolver un método devolviendo un valor nulo en un Option:

if (b) Some(hashMap.get(key)) else None 
// becomes --> 
None // the method was not invoked; 
Some(value) // the method was invoked and a value returned; or 
Some(null) // the method was invoked and null was returned. 

Some(null) parece suficientemente distinta de None en este caso, para justificar lo que permite que en el lenguaje.

Por supuesto, si esto no es deseable en su caso, entonces simplemente uso:

if (b) Option(hashMap.get(key)) else None 
// becomes --> 
None // the method was not invoked or the mapped value was null; or 
Some(value) // the method was invoked and a value returned 
8

Creo que los otros en el hilo hacen un buen trabajo explicando por qué Some(null) "debe" existir, pero si le toca estar Some(null) conseguir algún lugar y quieren una forma rápida para convertirlo en None, he hecho esto antes:

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

scala> x.flatMap(Option(_)) 
res8: Option[String] = None 

y cuando el Option de partida es un valor no nulo de fiar cosas funcionan como es probable que desee:

scala> val y: Option[String] = Some("asdf") 
y: Option[String] = Some(asdf) 

scala> y.flatMap(Option(_)) 
res9: Option[String] = Some(asdf) 
+1

De hecho, el "por qué" es interesante, pero la mayoría de nosotros probablemente se parezca más a "qué hacer a continuación". Muchas gracias. – fanfabbb

0

Debido opción se considera para ser una Functor y ser un Functor significa:

  1. Ha unit función (apply o simplemente Option("blah") en Scala)
  2. Ha map función que transforma el valor de T=>B pero no es un contexto
  3. Obeys 2 leyes Functor - ley de identidad y ley asociativa

En este tema, la parte principal es # 2 - Option(1).map(t=>null) no puede transformar el contexto. Some debe permanecer. ¡De lo contrario, frena la ley asociativa!

basta con considerar las siguientes leyes ejemplo:

def identity[T](v: T) = v 
def f1(v: String) = v.toUpperCase 
def f2(v: String) = v + v 
def fNull(v: String): String = null 

val opt = Option("hello") 

//identity law 
opt.map(identity) == opt //Some(hello) == Some(hello) 

//associative law 
opt.map(f1 _ andThen f2) == opt.map(f1).map(f2) //Some(HELLOHELLO) == Some(HELLOHELLO) 
opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) == Some(nullnull) 

Pero lo que si Option("hello").map(t=>null) producido None? ley asociativa se rompería:

opt.map(fNull _ andThen f2) == opt.map(fNull).map(f2) //Some(nullnull) != None 

Ese es mi pensamiento, que puede estar mal

Cuestiones relacionadas