F # 9: Opción de tipo

Si C # tiene el concepto de nulo para tipos de referencia y Nullabe para estructuras. Esto puede tomar una de las siguientes 2 formas (para demostración, uso el tipo int aquí, pero el tipo puede ser cualquier estructura).

  • Anulable
  • int?

Descargo de responsabilidad
   Nullabe  Nullable<T> ,    - ,    


Ambos son equivalentes.

La clase Nullable proporciona varias propiedades y métodos auxiliares que facilitan el trabajo con tipos y estructuras nulos. Estos son los siguientes:

  • Hasvalue
  • Valor
  • GetValueOrDefault ()
  • GetValueOrDefault (T)

Hay algo ligeramente diferente de F # en la forma de un tipo de Opción , que es un tipo más amigable para F # que prefiere no tratar con nulo, pero prefiere tratar con cosas en términos de "Puede contener el valor de tipo" o "Puede no tener valor ". Suena como Nullable, pero al final es del tipo F #, por lo que puede esperar que se use normalmente en cosas F #.

Otra cosa que vale la pena señalar con el tipo de opción F # es que se puede usar para cualquier tipo, no solo estructuras. Esto es diferente de .NET Nullable, que solo se puede usar con estructuras.

El valor None se usa cuando no hay valor; de lo contrario, la expresión Some (...) asigna un valor. Los valores Some y None se pueden usar cuando coinciden con un patrón, un ejemplo del cual veremos en esta publicación.

Al igual que Nullable, el tipo de opción F # tiene varias propiedades / métodos auxiliares, que se muestran en la tabla a continuación.

Ninguno
'Opción T
Una propiedad estática que le permite crear un valor de parámetro con un valor de Ninguno.
Isnone
bool
Devuelve verdadero si el parámetro es Ninguno.
Issome
bool
Devuelve verdadero si el parámetro tiene un valor diferente a Ninguno.
Algunos
'Opción T
Un miembro estático que crea un parámetro cuyo valor no es Ninguno.
Valor
'T
Devuelve un valor base o arroja una NullReferenceException si el valor es Ninguno.

Crear opciones


Entonces, ahora que sabemos qué son los tipos de Opción, cómo los creamos. Veamos algunos ejemplos. Tenga en cuenta que en este ejemplo, utilicé los métodos auxiliares IsSome / IsNone. Personalmente, creo que comparar con una muestra es la mejor manera, ya que te ayudará a comparar todos los casos, incluida la opción No.

De hecho, le mostraré lo fácil que es equivocarse cuando trabaja con los tipos de Opción si decide utilizar métodos auxiliares, pero primero veamos un ejemplo del caso correcto.

 let someInt = Some(43) let someString = Some("cat") let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let someInt = Some(43)" printfn "let someString = Some(\"cat\")" printfn "printTheOption (someInt)" printTheOption someInt printfn "printTheOption (someString)" printTheOption someString 

imagen

Pero, ¿qué pasa si lo intentamos nuevamente usando este código, donde tenemos Ninguno para el valor de Opción, que pasaremos a la función printTheOption:

 let demoNone = None let printTheOption (opt :Option<'a>) = printfn "Actual Option=%A" opt printfn "IsNone=%b, IsSome=%b Value=%A\r\n\r\n" opt.IsNone opt.IsSome opt.Value printfn "let demoNone = None" printfn "printTheOption demoNone" printTheOption demoNone 

imagen

Como puede ver, tenemos un problema aquí. El problema es que intentamos obtener el valor de la Opción usando la propiedad auxiliar Option.Value, en este caso es None, por lo que obtuvimos una NullReferenceException. En la tabla anterior se muestra que cuando usa propiedades y métodos auxiliares, puede obtener una excepción. Bueno, podría usar el método IsNone y siempre verificaría el valor usando esto cuando solo podría usar una buena coincidencia de patrón limpio.

Si no puede aceptar esto, pregúntese cuántas veces tuvo que verificar el valor nulo al usar C #. Esto incluso llevó a las personas a incluir construcciones funcionales, como Maybe Null Monad, en el código regular de .NET.

Entonces, ahora que hemos visto el peligro de usar métodos / propiedades auxiliares, volvamos nuestra atención a cómo podríamos evitar estas excepciones:

 et printTheOption (opt :Option<'a>) = match opt with | Some a -> printfn "opt is Some, and has value %A" a | None -> printfn "opt is None" let demoNone = None let someInt = Some 1 let someString = Some "crazy dude in the monkey house" printTheOption demoNone printTheOption someInt printTheOption someString 

Mi opinión personal es que es más legible que el código que estaría salpicado de IsSome / IsNone en todas partes. Esto, por supuesto, es asunto de todos, pero no se puede ignorar el hecho de que hemos cubierto todos los conceptos básicos aquí en esta sencilla función.

imagen

Opción vs nulo


Entonces, hablamos de Option en F # en comparación con Nullabe, y sabemos que el tipo Option puede usarse con cualquier tipo, mientras que Nullable solo puede usarse con estructuras. Pero, ¿qué pasa con los tipos de opciones en comparación con los tipos de referencia regulares en .NET? Bueno, una gran victoria para Option es que cuando usa el tipo de referencia en .NET, se trata de una referencia de puntero, que como tal se puede establecer en nulo. Sin embargo, el tipo del objeto sigue siendo el mismo que se declaró, que puede contener una referencia válida al objeto en el montón (Heap) o puede ser nulo.

Sería normal escribir así:

 string s1 = "cats"; int s1Length = s1.Length; string s2 = null; int s2Length = s2.Length; 

Esto se compilará con éxito. Sin embargo, cuando ejecutamos esto, obtendremos una NullReferenceException, por lo que nos veremos obligados a salir para proteger todo el código de la posible presencia de nulo. Esto se vuelve tedioso bastante rápido, incluso si tiene una pequeña clase de protección que verificará el valor y lo manejará / lanzará una excepción más significativa.

Esta captura de pantalla usa LinqPad, por lo que puede parecer un poco inusual si no ha visto LinqPad antes, pero créanme, todavía obtienen el mismo resultado en un IDE diferente.

imagen

Ahora veamos cómo se verá el código equivalente en F #

 let s1 = "Cats" let s1Length = s1.Length; let s2 = None let s2Length = s2.Length; //excplicily string typed None let s3 = Option.None let s3Length = s3.Length; 

En este código, obtendrá un error de compilación inmediato, ya que s3 se considerará otro tipo que no tiene la propiedad "Longitud".

Comparación de opciones


Los tipos de opción se consideran iguales, son del mismo tipo y los tipos que contienen son iguales, lo que obedece a las reglas de igualdad del tipo retenido.

Entonces, este tipo de cosas puede conducir a un error inmediato en tiempo de compilación en F #

 let o1 = Some 1 let o2 = Some "Cats" printfn "o1=o2 : %b" (o1 = o2) 

imagen

Esto funcionará como se esperaba ya que los tipos son los mismos

 let o1 = Some "Cats" let o2 = Some "Cats" let o3 = Some "cats" printfn "o1=o2 : %b" (o1 = o2) printfn "o2=o3 : %b" (o2 = o3) 

imagen

Source: https://habr.com/ru/post/470918/


All Articles