Partilhar via


Tipos flexíveis (F#)

A anotação de tipo flexível indica que um parâmetro, variável ou valor tem um tipo que seja compatível com um tipo especificado, onde a compatibilidade é determinada pela posição na hierarquia de orientada a objeto de classes ou interfaces. Tipos flexíveis são úteis especialmente quando a conversão automática de tipos mais altos na hierarquia de tipos não ocorre, mas deseja habilitar a funcionalidade trabalhar com qualquer tipo de hierarquia ou de qualquer tipo que implementa uma interface.

#type

Comentários

Na sintaxe anterior, type representa um tipo base ou uma interface.

Um tipo de flexível é equivalente a um tipo genérico que tem uma restrição que limita os tipos permitidos para tipos que são compatíveis com o tipo de base ou interface. Ou seja, as duas linhas de código a seguir são equivalentes.

#SomeType

'a when 'a :> SomeType

Tipos flexíveis são úteis em vários tipos de situações. Por exemplo, quando você tem uma função de ordem superior (uma função que usa uma função como um argumento), geralmente é útil ter a função para retornar um tipo flexível. No exemplo a seguir, o uso de um tipo flexível com um argumento de seqüência em iterate2 permite que a função de ordem superior para trabalhar com funções que geram seqüências, matrizes, listas e quaisquer outros enumerable tipo.

Considere duas funções a seguir, um dos quais retorna uma seqüência, outros dos quais retorna um tipo flexível.

let iterate1 (f : unit -> seq<int>) =
    for e in f() do printfn "%d" e
let iterate2 (f : unit -> #seq<int>) =
    for e in f() do printfn "%d" e

// Passing a function that takes a list requires a cast.
iterate1 (fun () -> [1] :> seq<int>)

// Passing a function that takes a list to the version that specifies a
// flexible type as the return value is OK as is.
iterate2 (fun () -> [1])

Como outro exemplo, considere a Seq.concat a função de biblioteca:

val concat: sequences:seq<#seq<'T>> -> seq<'T>

Você pode passar qualquer uma das seguintes seqüências enumerable para esta função:

  • Uma lista de listas

  • Uma lista de matrizes

  • Uma matriz de listas

  • Uma matriz de seqüências

  • Qualquer outra combinação de seqüências de enumerable

O seguinte código usa Seq.concat para demonstrar os cenários em que você pode suportar usando tipos flexíveis.

let list1 = [1;2;3]
let list2 = [4;5;6]
let list3 = [7;8;9]

let concat1 = Seq.concat [ list1; list2; list3]
printfn "%A" concat1

let array1 = [|1;2;3|]
let array2 = [|4;5;6|]
let array3 = [|7;8;9|]

let concat2 = Seq.concat [ array1; array2; array3 ]
printfn "%A" concat2

let concat3 = Seq.concat [| list1; list2; list3 |]
printfn "%A" concat3

let concat4 = Seq.concat [| array1; array2; array3 |]
printfn "%A" concat4

let seq1 = { 1 .. 3 }
let seq2 = { 4 .. 6 }
let seq3 = { 7 .. 9 }

let concat5 = Seq.concat [| seq1; seq2; seq3 |]

printfn "%A" concat5

A saída é da seguinte maneira.

seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]

No F#, como em outras linguagens orientadas a objeto, há contextos em que tipos derivados ou tipos que implementam as interfaces são convertidos automaticamente para um tipo base ou interface. Essas conversões automáticas ocorrem nos argumentos diretos, mas não quando o tipo está em uma posição subordinada, como parte de um tipo mais complexo, como, por exemplo, um tipo de retorno de um tipo de função, ou como um argumento de tipo. Assim, a notação de tipo flexível é útil principalmente quando o tipo que você está aplicando o que ele é parte de um tipo mais complexo.

Consulte também

Referência

Genéricos (F#)

Outros recursos

Referência de linguagem do F#