Opções
O tipo de opção em F# é usado quando um valor real pode não existir para um valor ou variável nomeado. Uma opção tem um tipo subjacente e pode conter um valor desse tipo ou pode não ter um valor.
Comentários
O código a seguir ilustra uma função que gera um tipo de opção.
let keepIfPositive (a: int) = if a > 0 then Some(a) else None
Como você pode ver, se a entrada a
for maior que 0, Some(a)
será gerado. Caso contrário, None
é gerado.
O valor None
é usado quando uma opção não tem um valor real. Caso contrário, a expressão Some( ... )
fornecerá um valor à opção. Os valores Some
e None
são úteis em padrões correspondentes, como na função exists
a seguir, que retorna true
se a opção tiver um valor e false
se não tiver.
let exists (x: int option) =
match x with
| Some(x) -> true
| None -> false
Usando opções
As opções são comumente usadas quando uma pesquisa não retorna um resultado correspondente, conforme mostra o código a seguir.
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 ]
No código anterior, uma lista é pesquisada recursivamente. A função tryFindMatch
usa uma função de predicado pred
que retorna um valor booliano e uma lista a ser pesquisada. Se um elemento que satisfaz o predicado for encontrado, a recursão terminará e a função retornará o valor como uma opção na expressão Some(head)
. A recursão termina quando a lista vazia é correspondida. Nesse ponto, o valor head
não foi encontrado e None
é retornado.
Muitas funções de biblioteca F# que pesquisam uma coleção em busca de um valor que pode ou não existir retornam o tipo option
. Por convenção, essas funções começam com o prefixo try
, por exemplo, Seq.tryFindIndex
.
As opções também podem ser úteis quando um valor pode não existir, por exemplo, se for possível que uma exceção seja gerada quando você tenta construir um valor. O exemplo de código a seguir ilustra isso.
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
A função openFile
no exemplo anterior tem tipo string -> File option
porque retorna um objeto File
se o arquivo é aberto com êxito e None
se ocorre uma exceção. Dependendo da situação, pode não ser uma opção de design apropriada capturar uma exceção em vez de permitir que ela se propague.
Além disso, ainda é possível passar null
ou um valor nulo para o caso Some
de uma opção. Isso geralmente deve ser evitado e, normalmente, está na programação F# de rotina, mas é possível devido à natureza dos tipos de referência no .NET.
Propriedades e métodos da opção
O tipo de opção dá suporte às seguintes propriedades e métodos.
Propriedade ou método | Tipo | Descrição |
---|---|---|
None |
'T option |
Um membro estático que cria um valor de opção que tem o valor None . |
IsNone | bool |
Retornará true se a opção tiver o valor None . |
IsSome | bool |
Retornará true se a opção tiver um valor que não seja None . |
Some |
'T option |
Um membro estático que cria uma opção que tem um valor que não é None . |
Valor | 'T |
Retorna o valor subjacente ou gera um System.NullReferenceException se o valor for None . |
Módulo Option
Há um módulo, Option, que contém funções úteis que executam operações em opções. Algumas funções repetem a funcionalidade das propriedades, mas são úteis em contextos em que uma função é necessária. Option.isSome e Option.isNone são funções de módulo que testam se uma opção contém um valor. Option.get obtém o valor, se houver um. Se não houver valor, System.ArgumentException
será gerado.
A função Option.bind executa uma função no valor, se houver um valor. A função deve ter exatamente um argumento e seu tipo de parâmetro deve ser o tipo de opção. O valor retornado da função é outro tipo de opção.
O módulo de opção também inclui funções que correspondem às funções disponíveis para listas, matrizes, sequências e outros tipos de coleção. Essas funções incluem Option.map
, Option.iter
, Option.forall
, Option.exists
, Option.foldBack
, Option.fold
e Option.count
. Essas funções permitem que as opções sejam usadas como uma coleção de zero ou um elemento. Para mais informações e exemplos, confira a discussão das funções de coleção em Listas.
Como converter em outros tipos
As opções podem ser convertidas em listas ou matrizes. Quando uma opção é convertida em qualquer uma dessas estruturas de dados, a estrutura de dados resultante tem zero ou um elemento. Para converter uma opção em uma matriz, use Option.toArray
. Para converter uma opção em uma lista, use Option.toList
.