Valores NULL
En este tema se describe cómo se usa el valor NULL en F#.
Valores NULL anteriores a F# 9
El valor NULL no se usa normalmente en F# para valores o variables. Sin embargo, null aparece como un valor anómalo en determinadas situaciones. Si un tipo se define en F#, null no se permite como un valor normal a menos que el AllowNullLiteral atributo se aplique al tipo. Si se define un tipo en algún otro lenguaje .NET, null es un valor posible y, al interoperar con estos tipos, el código de F# podría encontrar valores NULL.
Para un tipo definido en F# y utilizado estrictamente desde F#, la única manera de crear un valor null utilizando directamente la biblioteca de F# es usar Unchecked.defaultof o Array.zeroCreate. Sin embargo, para un tipo de F# que se usa desde otros lenguajes .NET, o si usa ese tipo con una API que no está escrita en F#, como .NET Framework, pueden producirse valores NULL.
Puede usar el tipo de option
en F# cuando pueda usar una variable de referencia con un posible valor NULL en otro lenguaje .NET. En lugar de null, con un tipo F# option
, usas el valor de opción None
si no hay ningún objeto. El valor de opción Some(obj)
se usa con un objeto obj
cuando hay un objeto. Para obtener más información, vea Opciones. Tenga en cuenta que todavía puede empaquetar un valor null
en una opción si se da la circunstancia de que, para Some x
, x
es null
. Por este motivo, es importante usar None
cuando un valor es null
.
La palabra clave null
es una palabra clave válida en F#, y debe usarla cuando se trabaja con las API de .NET Framework u otras API escritas en otro lenguaje .NET. Las dos situaciones en las que es posible que necesite un valor NULL son cuando se llama a una API de .NET y se pasa un valor NULL como argumento, y al interpretar el valor devuelto o un parámetro de salida de una llamada al método .NET.
Para pasar un valor NULL a un método .NET, use la palabra clave null
en el código de llamada. En el ejemplo de código siguiente se muestra esto.
open System
// Pass a null value to a .NET method.
let ParseDateTime (str: string) =
let (success, res) =
DateTime.TryParse(str, null, System.Globalization.DateTimeStyles.AssumeUniversal)
if success then Some(res) else None
Para interpretar un valor NULL que se obtiene de un método .NET, use la coincidencia de patrones si es posible. En el ejemplo de código siguiente se muestra cómo usar la coincidencia de patrones para interpretar el valor NULL que se devuelve de ReadLine
cuando intenta leer más allá del final de una secuencia de entrada.
// Open a file and create a stream reader.
let fileStream1 =
try
System.IO.File.OpenRead("TextFile1.txt")
with :? System.IO.FileNotFoundException ->
printfn "Error: TextFile1.txt not found."
exit (1)
let streamReader = new System.IO.StreamReader(fileStream1)
// ProcessNextLine returns false when there is no more input;
// it returns true when there is more input.
let ProcessNextLine nextLine =
match nextLine with
| null -> false
| inputString ->
match ParseDateTime inputString with
| Some(date) -> printfn "%s" (date.ToLocalTime().ToString())
| None -> printfn "Failed to parse the input."
true
// A null value returned from .NET method ReadLine when there is
// no more input.
while ProcessNextLine(streamReader.ReadLine()) do
()
Los valores nulos para los tipos de F# también se pueden generar de otras maneras, por ejemplo, cuando se usa Array.zeroCreate
, que llama a Unchecked.defaultof
. Debe tener cuidado con este código para mantener encapsulados los valores NULL. En una biblioteca diseñada solo para F#, no es necesario comprobar si hay valores NULL en cada función. Si está escribiendo una biblioteca para la interoperación con otros lenguajes .NET, es posible que tenga que agregar comprobaciones de parámetros de entrada NULL y generar un objeto ArgumentNullException
, igual que en el código de C# o Visual Basic.
Puede usar el código siguiente para comprobar si un valor arbitrario es NULL.
match box value with
| null -> printf "The value is null."
| _ -> printf "The value is not null."
Valores nulos a partir de F# 9
En F# 9, se agregan funcionalidades adicionales al lenguaje para tratar los tipos de referencia que pueden tener null
como valor. Estos están desactivados de forma predeterminada: para activarlos, la siguiente propiedad debe colocarse en el archivo del proyecto:
<Nullable>enable</Nullable>
Esto pasa la marca de --checknulls+
al compilador de F# y establece una directiva de preprocesador NULLABLE
para la compilación.
Para participar explícitamente en la nulabilidad, se debe sufijar una declaración de tipo con la nueva sintaxis:
type | null
El símbolo |
tiene el significado de un OR lógico en la sintaxis, creando una unión de dos conjuntos disjuntos de tipos: el tipo subyacente y la referencia anulable. Este es el mismo símbolo sintáctico que se usa para declarar varios casos de una unión discriminada de F#: type AB = A | B
lleva el significado de A
o B
.
La anotación que acepta valores NULL | null
se puede utilizar en todos los lugares donde normalmente se emplearía un tipo de referencia.
- Campos de tipos de unión, tipos de registro y tipos personalizados.
- Alias de tipo para tipos existentes.
- Escriba aplicaciones de un tipo genérico.
- Anotaciones de tipo explícitas para permitir enlaces, parámetros o tipos devueltos.
- Escriba anotaciones en construcciones de programación de objetos como miembros, propiedades o campos.
type AB = A | B
type AbNull = AB | null
type RecordField = { X: string | null }
type TupleField = string * string | null
type NestedGenerics = { Z : List<List<string | null> | null> | null }
El símbolo de barra |
tiene otros usos en F# que podrían provocar ambigüedades sintácticas. En tales casos, se necesitan paréntesis alrededor del tipo anotado con null:
// Unexpected symbol '|' (directly before 'null') in member definition
type DUField = N of string | null
Encerrar el mismo tipo en un par de paréntesis ( )
corrige el problema.
type DUField = N of (string | null)
Cuando se usa en la coincidencia de patrones, se usa |
para separar diferentes cláusulas de coincidencia de patrones.
match x with
| ?: string | null -> ...
Este fragmento de código es realmente equivalente al código que realiza primero una prueba de tipo en el tipo string
y, a continuación, tiene una cláusula independiente para controlar null:
match x with
| ?: string
| null -> ...
Importante
Las funcionalidades adicionales relacionadas con null se agregaron al lenguaje con fines de interoperabilidad. El uso de | null
en el modelado de tipos de F# no se considera idiomático para indicar que falta información; para ello, use las opciones (como se ha descrito anteriormente). Obtenga más información sobre las convenciones relacionadas con null en la guía de estilo.