Opciones
El tipo de opción de F# se usa cuando es posible que un valor real no exista para un valor con nombre o una variable. Una opción tiene un tipo subyacente y puede contener un valor de ese tipo o podría no tener un valor.
Observaciones
En el código siguiente se muestra una función que genera un tipo de opción.
let keepIfPositive (a: int) = if a > 0 then Some(a) else None
Como puede ver, si el a
de entrada es mayor que 0, se genera Some(a)
. De lo contrario, se genera None
.
El valor None
se usa cuando una opción no tiene un valor real. De lo contrario, la expresión Some( ... )
proporciona un valor a la opción . Los valores Some
y None
son útiles en la coincidencia de patrones, como en la función siguiente exists
, que devuelve true
si la opción tiene un valor y false
si no lo hace.
let exists (x: int option) =
match x with
| Some(x) -> true
| None -> false
Uso de opciones
Las opciones se suelen usar cuando una búsqueda no devuelve un resultado coincidente, como se muestra en el código siguiente.
let rec tryFindMatch pred list =
match list with
| head :: tail -> if pred (head) then Some(head) else tryFindMatch pred tail
| [] -> None
// result1 is Some 100 and its type is int option.
let result1 = tryFindMatch (fun elem -> elem = 100) [ 200; 100; 50; 25 ]
// result2 is None and its type is int option.
let result2 = tryFindMatch (fun elem -> elem = 26) [ 200; 100; 50; 25 ]
En el código anterior, se busca una lista de forma recursiva. La función tryFindMatch
toma una función de predicado pred
que devuelve un valor booleano y una lista para buscar. Si se encuentra un elemento que satisface el predicado, la recursividad finaliza y la función devuelve el valor como una opción en la expresión Some(head)
. La recursividad finaliza cuando se coincide con la lista vacía. En ese momento no se encontró el valor head
y se devuelve None
.
Muchas funciones de biblioteca de F# que buscan una colección para un valor que puede o no existir devuelven el tipo de option
. Por convención, estas funciones comienzan con el prefijo try
, por ejemplo, Seq.tryFindIndex
.
Las opciones también pueden ser útiles cuando es posible que un valor no exista, por ejemplo, si es posible que se produzca una excepción al intentar construir un valor. En el ejemplo de código siguiente se muestra esto.
open System.IO
let openFile filename =
try
let file = File.Open(filename, FileMode.Create)
Some(file)
with ex ->
eprintf "An exception occurred with message %s" ex.Message
None
La función openFile
del ejemplo anterior tiene string -> File option
de tipo porque devuelve un objeto File
si el archivo se abre correctamente y None
si se produce una excepción. En función de la situación, puede que no sea una opción de diseño adecuada para detectar una excepción en lugar de permitir que se propague.
Además, todavía es posible pasar null
o un valor que sea NULL al Some
caso de una opción. Esto suele evitarse y normalmente está en programación de F# rutinaria, pero es posible debido a la naturaleza de los tipos de referencia en .NET.
Propiedades y métodos de opción
El tipo de opción admite las siguientes propiedades y métodos.
Propiedad o método | Tipo | Descripción |
---|---|---|
None |
'T option |
Miembro estático que crea un valor de opción que tiene el valor de None . |
IsNone | bool |
Devuelve true si la opción tiene el valor None . |
IsSome | bool |
Devuelve true si la opción tiene un valor que no es None . |
Some |
'T option |
Miembro estático que crea una opción que tiene un valor que no es None . |
Valor | 'T |
Devuelve el valor subyacente o produce un System.NullReferenceException si el valor es None . |
Módulo opcional
Hay un módulo, Option, que contiene funciones útiles que realizan operaciones en opciones. Algunas funciones repiten la funcionalidad de las propiedades, pero son útiles en contextos en los que se necesita una función. Option.isSome y Option.isNone son funciones de módulo que prueban si una opción contiene un valor. Option.get obtiene el valor, si hay uno. Si no hay ningún valor, inicia System.ArgumentException
.
La función Option.bind ejecuta una función en el valor, si hay un valor. La función debe tomar exactamente un argumento y su tipo de parámetro debe ser el tipo de opción. El valor devuelto de la función es otro tipo de opción.
El módulo de opciones también incluye funciones que corresponden a las funciones que están disponibles para listas, matrices, secuencias y otros tipos de colección. Estas funciones incluyen Option.map
, Option.iter
, Option.forall
, Option.exists
, Option.foldBack
, Option.fold
y Option.count
. Estas funciones permiten usar opciones como una colección de uno o cero elementos. Para obtener más información y ejemplos, vea la explicación de las funciones de colección en Listas.
Conversión a otros tipos
Las opciones se pueden convertir en listas o matrices. Cuando se convierte una opción en cualquiera de estas estructuras de datos, la estructura de datos resultante tiene cero o un elemento. Para convertir una opción en una matriz, use Option.toArray
. Para convertir una opción en una lista, use Option.toList
.
Conversión de opciones con valores predeterminados
Además de convertir en listas y matrices, las opciones se pueden convertir a otros tipos proporcionando valores predeterminados mediante la función Option.defaultValue
. Esto resulta especialmente útil cuando desea asegurarse de que el valor no es None
. Por ejemplo:
let optionString = Some("F#")
let defaultString = optionString |> Option.defaultValue ""
// defaultString is "F#"
let optionInt = None
let defaultInt = optionInt |> Option.defaultValue 0
// defaultInt is 0
La función Option.defaultValue
permite manejar sin problemas tanto los casos Some
como None
sin coincidencias de patrones.