Valores nulos
Este tópico descreve como o valor nulo é usado em F#.
Valores nulos anteriores ao F# 9
O valor nulo normalmente não é usado em F# para valores ou variáveis. No entanto, null aparece como um valor anormal em determinadas situações. Se um tipo for definido em F#, null não será permitido como um valor regular, a menos que o atributo AllowNullLiteral seja aplicado ao tipo. Se um tipo é definido em alguma outra linguagem .NET, null é um valor possível, e quando você está interoperando com esses tipos, seu código F# pode encontrar valores nulos.
Para um tipo definido em F# e usado estritamente a partir de F#, a única maneira de criar um valor nulo usando a biblioteca F# diretamente é usar Unchecked.defaultof ou Array.zeroCreate. No entanto, para um tipo de F# que é usado de outras linguagens .NET, ou se você estiver usando esse tipo com uma API que não está escrita em F#, como o .NET Framework, valores nulos podem ocorrer.
Você pode usar o tipo option
em F# quando puder usar uma variável de referência com um possível valor nulo em outra linguagem .NET. Em vez de null, com um tipo F# option
, utilize o valor de opção None
se não houver objeto. Use o valor da opção Some(obj)
com um objeto obj
quando há um objeto. Para obter mais informações, consulte as opções e. Observe que você ainda pode empacotar um valor de null
em uma Opção se, por Some x
, x
acontecer de ser null
. Por isso, é importante que você use None
quando um valor é null
.
A palavra-chave null
é uma palavra-chave válida em F#, e você precisa usá-la quando estiver trabalhando com APIs do .NET Framework ou outras APIs escritas em outra linguagem .NET. As duas situações em que você pode precisar de um valor nulo são quando você chama uma API .NET e passa um valor nulo como um argumento, e quando você interpreta o valor de retorno ou um parâmetro de saída de uma chamada de método .NET.
Para passar um valor nulo para um método .NET, basta usar a palavra-chave null
no código de chamada. O exemplo de código a seguir ilustra isso.
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 um valor nulo que é obtido de um método .NET, use a correspondência de padrão, se possível. O exemplo de código a seguir mostra como usar a correspondência de padrão para interpretar o valor nulo que é retornado de ReadLine
quando ele tenta ler além do final de um fluxo 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
()
Valores nulos para tipos F# também podem ser gerados de outras maneiras, como quando você usa Array.zeroCreate
, que chama Unchecked.defaultof
. Você deve ter cuidado com esse código para manter os valores nulos encapsulados. Em uma biblioteca destinada apenas a F#, não é necessário verificar valores nulos em todas as funções. Se você estiver escrevendo uma biblioteca para interoperação com outras linguagens .NET, talvez seja necessário adicionar verificações para parâmetros de entrada nulos e lançar um ArgumentNullException
, assim como faz no código C# ou Visual Basic.
Você pode usar o código a seguir para verificar se um valor arbitrário é nulo.
match box value with
| null -> printf "The value is null."
| _ -> printf "The value is not null."
Valores nulos começando com F# 9
No F# 9, recursos extras são adicionados à linguagem para lidar com tipos de referência que podem ter null
como um valor. Estes estão desativados por padrão - para ativá-los, a seguinte propriedade deve ser colocada em seu arquivo de projeto:
<Nullable>enable</Nullable>
Isso passa o sinalizador --checknulls+
para o compilador F# e define uma NULLABLE
diretiva de pré-processador para a compilação.
Para aceitar explicitamente a anulabilidade, uma declaração de tipo deve ser sufixada com a nova sintaxe:
type | null
O símbolo de barra |
tem o significado de um OR lógico na sintaxe, construindo uma união de dois conjuntos disjuntos de tipos: o tipo subjacente e a referência anulável. Este é o mesmo símbolo sintático que é usado para declarar vários casos de uma união discriminada F#: type AB = A | B
carrega o significado de A
, ou B
.
A anotação anulável | null
pode ser usada em todos os locais onde um tipo de referência seria normalmente usado:
- Campos de tipos de união, tipos de registro e tipos personalizados.
- Defina alias para tipos existentes.
- Digite aplicações de um tipo genérico.
- Anotações de tipo explícitas para permitir associações, parâmetros ou tipos de retorno.
- Digite anotações para construções de programação de objetos como membros, propriedades ou 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 }
O símbolo de barra |
tem outros usos em F# que podem levar a ambiguidades sintáticas. Nesses casos, são necessários parênteses em torno do tipo anotado nulo:
// Unexpected symbol '|' (directly before 'null') in member definition
type DUField = N of string | null
Envolver o mesmo tipo num par de ( )
parênteses corrige o problema:
type DUField = N of (string | null)
Quando usado na correspondência de padrões, |
é usado para separar diferentes cláusulas de correspondência de padrões.
match x with
| ?: string | null -> ...
Esse trecho é, na verdade, equivalente ao código primeiro fazendo um teste de tipo em relação ao tipo string
e, em seguida, tendo uma cláusula separada para lidar com null:
match x with
| ?: string
| null -> ...
Importante
Capacidades extra relacionadas com nulos foram adicionadas à linguagem com o objetivo de interoperabilidade. O uso de | null
na modelagem de tipo F# não é considerado idiomática para denotar informações ausentes - para esse fim, use opções (conforme descrito acima). Leia mais sobre convenções relacionadas com nulos no guia de estilo.