Genéricos (F#)
A função F# valores, métodos, propriedades e agregação tipos como classes, registra e uniões discriminadas podem ser genérico.Construções genéricas contenham pelo menos um parâmetro de tipo, que é geralmente fornecido pelo usuário da construção genérico.Tipos e funções genéricas permitem que você escrever código que funciona com uma variedade de tipos sem repetir o código para cada tipo.Tornando o código genérico pode ser simple em F#, porque geralmente seu código é implicitamente inferido para ser genérico, inferência de tipos do compilador e mecanismos de generalização automática.
// Explicitly generic function.
let function-name<type-parameters> parameter-list =
function-body
// Explicitly generic method.
[ static ] member object-identifer.method-name<type-parameters> parameter-list [ return-type ] =
method-body
// Explicitly generic class, record, interface, structure,
// or discriminated union.
type type-name<type-parameters> type-definition
Comentários
A declaração de uma função genérica explicitamente ou o tipo é semelhante a de uma função não genérico ou tipo, exceto para a especificação (e o uso) os parâmetros de tipo, colchetes angulares após o nome de função ou tipo.
Declarações costumam ser implicitamente genéricas.Se você não especificar o tipo de cada parâmetro que é usado para compor uma função ou um tipo totalmente, o compilador tentará deduzir o tipo de cada parâmetro, o valor e a variável a partir do código que você escreve.Para obter mais informações, consulte Inferência de tipo (F#).Se o código para o seu tipo ou a função não restringir os tipos de parâmetros caso contrário, a função ou tipo é implicitamente genérico.Esse processo é chamado de automática generalização.Há alguns limites na generalização automática.Por exemplo, se o compilador F# for não é possível inferir os tipos para uma construção genérico, o compilador reporta um erro que se refere a uma restrição chamada a a restrição de valor.Nesse caso, talvez você precise adicionar algumas anotações de tipo.Para obter mais informações sobre como alterar o seu código para resolver o problema e a restrição de valor e generalização automática, consulte Generalização automática (F#).
Na sintaxe anterior, type-parameters é uma lista separada por vírgulas de parâmetros que representam tipos desconhecidos, cada um deles começa com uma aspa, opcionalmente com uma cláusula constraint que ainda mais limita os tipos pode ser usada para esse parâmetro de tipo.Para a sintaxe de cláusulas constraint de vários tipos e outras informações sobre as restrições, consulte Restrições (F#).
O type-definition na sintaxe é o mesmo que a definição de tipo para um tipo não genérico.Ele inclui os parâmetros de construtor para um tipo de classe, um recurso opcional as cláusula, o símbolo de igual, os campos do registros, o inherit cláusula, as opções para uma união discriminada, let e do ligações, definições de membro e qualquer outra coisa permitida em uma definição de tipo não genérico.
Os outros elementos de sintaxe são as mesmas para tipos e funções não-genéricas.Por exemplo, object-identifier é um identificador que representa o próprio objeto de recipiente.
Construtores, campos e propriedades não podem ser mais genéricos que o tipo de delimitador.Além disso, os valores em um módulo não podem ser genéricos.
Construções implicitamente genéricas
Quando o compilador F# infere os tipos no seu código, ele automaticamente trata qualquer função que pode ser genérica como genéricos.Se você especificar um tipo explicitamente, como, por exemplo, um tipo de parâmetro, você impede que a generalização automática.
No exemplo de código a seguir, makeList é genérico, mesmo que nem ele nem seus parâmetros são explicitamente declarados como genéricos.
let makeList a b =
[a; b]
A assinatura da função é inferida para ser 'a -> 'a -> 'a list.Observe que a e b neste exemplo são inferidos para ter o mesmo tipo.Isso ocorre porque eles são incluídos em uma lista juntos e todos os elementos de uma lista devem ser do mesmo tipo.
Você também pode fazer uma função genérica usando a sintaxe das aspas simples em uma anotação de tipo para indicar que um tipo de parâmetro é um parâmetro de tipo genérico.No código a seguir, function1 é genérica, porque seus parâmetros são declarados dessa maneira, como parâmetros de tipo.
let function1 (x: 'a) (y: 'a) =
printfn "%A %A" x y
Construções explicitamente genéricas
Você também pode fazer uma função genérica declarando explicitamente seus tipos de parâmetros em colchetes angulares (< >).O código a seguir ilustra isso.
let function2<'T> x y =
printfn "%A, %A" x y
Usar genérico construções.
Quando você usa métodos ou funções genéricas, você talvez não tenha que especificar os argumentos de tipo.O compilador usa a inferência de tipos para inferir os argumentos de tipo apropriado.Se ainda existe uma ambigüidade, você pode fornecer os argumentos de tipo em colchetes angulares, separando vários argumentos de tipo com vírgulas.
O código a seguir mostra o uso das funções que são definidos nas seções anteriores.
// In this case, the type argument is inferred to be int.
function1 10 20
// In this case, the type argument is float.
function1 10.0 20.0
// Type arguments can be specified, but should only be specified
// if the type parameters are declared explicitly. If specified,
// they have an effect on type inference, so in this example,
// a and b are inferred to have type int.
let function3 a b =
// The compiler reports a warning:
function1<int> a b
// No warning.
function2<int> a b
Observação |
---|
Há duas maneiras para se referir a um tipo genérico pelo nome.Por exemplo, list<int> e int list de duas maneiras para se referir a um tipo genérico list que tem um argumento de tipo único int.O último formulário é usado somente com F# tipos internos, como list e option.Se houver vários argumentos de tipo, você normalmente usa a sintaxe Dictionary<int, string> , mas você também pode usar a sintaxe (int, string) Dictionary. |
Caracteres curinga como argumentos de tipo
Para especificar que um argumento de tipo deve ser inferido pelo compilador, você pode usar o sublinhado ou um símbolo de caractere curinga (_), em vez de um argumento de tipo nomeado.Isto é mostrado no código a seguir.
let printSequence (sequence1: Collections.seq<_>) =
Seq.iter (fun elem -> printf "%s " (elem.ToString())) sequence1
Restrições em tipos genéricos e funções
Em um tipo genérico ou definição de função, você pode usar somente a construções que são conhecidas por estar disponível no parâmetro de tipo genérico.Isso é necessário para ativar a verificação de chamadas de função e método em tempo de compilação.Se você declarar explicitamente os parâmetros de tipo, você pode aplicar uma restrição explícita a um parâmetro de tipo genérico para notificar o compilador que determinadas funções e métodos estão disponíveis.No entanto, se você permitir que o compilador inferir os tipos de parâmetro genérico F#, ele determinará as restrições apropriadas para você.Para obter mais informações, consulte Restrições (F#).
Resolvido estaticamente os parâmetros de tipo
Existem dois tipos de parâmetros de tipo que podem ser usados em programas de F#.A primeira são os parâmetros de tipo genérico do tipo descrito nas seções anteriores.Esse primeiro tipo de parâmetro de tipo é equivalente aos parâmetros de tipo genérico que são usados em linguagens como, por exemplo, Visual Basic e C#.Outro tipo de parâmetro de tipo é específico para F# e é conhecido como um resolvido estaticamente o parâmetro de tipo.Para obter informações sobre essas construções, consulte Resolvido estaticamente os parâmetros de tipo (F#).
Exemplos
// A generic function.
// In this example, the generic type parameter 'a makes function3 generic.
let function3 (x : 'a) (y : 'a) =
printf "%A %A" x y
// A generic record, with the type parameter in angle brackets.
type GR<'a> =
{
Field1: 'a;
Field2: 'a;
}
// A generic class.
type C<'a>(a : 'a, b : 'a) =
let z = a
let y = b
member this.GenericMethod(x : 'a) =
printfn "%A %A %A" x y z
// A generic discriminated union.
type U<'a> =
| Choice1 of 'a
| Choice2 of 'a * 'a
type Test() =
// A generic member
member this.Function1<'a>(x, y) =
printfn "%A, %A" x y
// A generic abstract method.
abstract abstractMethod<'a, 'b> : 'a * 'b -> unit
override this.abstractMethod<'a, 'b>(x:'a, y:'b) =
printfn "%A, %A" x y
Consulte também
Referência
Resolvido estaticamente os parâmetros de tipo (F#)