Restrições (F#)
Este tópico descreve as restrições que você pode aplicar aos parâmetros de tipo genéricos para especificar os requisitos para um argumento de tipo em um tipo genérico ou em uma função.
type-parameter-list when constraint1 [ and constraint2]
Comentários
Há várias restrições diferentes que você pode aplicar para limitar os tipos que podem ser usados em um tipo genérico.A tabela a seguir lista e descreve as restrições.
Restrições |
Sintaxe |
Descrição |
---|---|---|
Restrição de tipo |
type-parameter : > type |
O tipo fornecido deve ser igual a ou derivado do tipo especificado, ou, se tipo é uma interface, o tipo fornecido deve implementar a interface. |
Restrição nula |
type-parameter : nulo |
O tipo fornecido deve suportar o literal nulo.Isso inclui todos os tipos de objeto .NET mas não lista de F#, tuple, função, classe, registro, ou tipos de união. |
Restrição explícita de membro |
([] [type-parameter ou…ou type-parameter)] : (member-signature) |
Pelo menos um dos argumentos de tipo fornecido deve ter um membro que possui a assinatura especificada; não servem para uso comum. |
Restrição de construtor |
type-parameter : (novo: - > a unidade ') |
O tipo fornecido deve ter um construtor padrão. |
Restrição de tipo de valor |
: estrutura |
O tipo fornecido deve ser um tipo de valor .NET. |
Restrição de tipo de referência |
: não estrutura |
O tipo fornecido deve ser um tipo de referência .NET. |
Restrição de tipo de enumeração |
: enum<underlying-type> |
O tipo fornecido deve ser um tipo enumerado que tem o tipo subjacente especificado; não servem para uso comum. |
Restrição de representante |
: delegate<tuple-parameter-type, return-type> |
O tipo fornecido deve ser um tipo delegado que tenha os argumentos e o valor de retorno especificados; não servem para uso comum. |
Restrição de comparação |
: comparação |
O tipo fornecido deve oferecer suporte a comparação. |
Restrição de igualdade |
: igualdade |
O tipo fornecido deve oferecer suporte a igualdade. |
Restrição não gerenciado |
: não gerenciado |
O tipo fornecido deve ser um tipo não gerenciado.Os tipos não gerenciado são determinados tipos primitivos (sbyte, byte, char, nativeint, unativeint, float32, float, int16, uint16, int32, uint32, int64, uint64, ou decimal), tipos de enumeração, nativeptr<_>, ou uma estrutura não genéricos cujos os campos são todas tipos não gerenciado. |
Você precisa adicionar uma restrição quando seu código precisa usar um recurso que está disponível no tipo de restrição mas não em tipos em geral.Por exemplo, se você usar a restrição de tipo para especificar um tipo de classe, você pode usar qualquer um dos métodos dessa classe na função ou no tipo genérico.
Especificar restrições às vezes é necessário ao escrever parâmetros de tipo explicitamente, porque sem uma restrição, o compilador não tem nenhuma maneira para verificar se os recursos que você está usando estão disponíveis em qualquer tipo que pode ser fornecido em tempo de execução para o parâmetro de tipo.
Restrições que a mais comum você usa em F# o código são as restrições do tipo que especificam classes base ou interfaces.Outras restrições são uma usada pela biblioteca de F# para implementar uma determinada funcionalidade, como a restrição explícita de membros, que é usada para implementar a sobrecarga de operador para operadores aritméticos, ou são fornecidas especialmente porque F# oferece suporte ao conjunto completo de restrições que são suportados pelo common language runtime.
Durante o processo de inferência de tipos, algumas restrições são inferidas automaticamente pelo compilador.Por exemplo, se você usar o operador de + em uma função, o compilador infere uma restrição explícita de membros em tipos de variáveis que são usadas na expressão.
O código a seguir ilustra algumas declarações de restrição.
// Base Type Constraint
type Class1<'T when 'T :> System.Exception> =
class end
// Interface Type Constraint
type Class2<'T when 'T :> System.IComparable> =
class end
// Null constraint
type Class3<'T when 'T : null> =
class end
// Member constraint with static member
type Class4<'T when 'T : (static member staticMethod1 : unit -> 'T) > =
class end
// Member constraint with instance member
type Class5<'T when 'T : (member Method1 : 'T -> int)> =
class end
// Member constraint with property
type Class6<'T when 'T : (member Property1 : int)> =
class end
// Constructor constraint
type Class7<'T when 'T : (new : unit -> 'T)>() =
member val Field = new 'T()
// Reference type constraint
type Class8<'T when 'T : not struct> =
class end
// Enumeration constraint with underlying value specified
type Class9<'T when 'T : enum<uint32>> =
class end
// 'T must implement IComparable, or be an array type with comparable
// elements, or be System.IntPtr or System.UIntPtr. Also, 'T must not have
// the NoComparison attribute.
type Class10<'T when 'T : comparison> =
class end
// 'T must support equality. This is true for any type that does not
// have the NoEquality attribute.
type Class11<'T when 'T : equality> =
class end
type Class12<'T when 'T : delegate<obj * System.EventArgs, unit>> =
class end
type Class13<'T when 'T : unmanaged> =
class end
// Member constraints with two type parameters
// Most often used with static type parameters in inline functions
let inline add(value1 : ^T when ^T : (static member (+) : ^T * ^T -> ^T), value2: ^T) =
value1 + value2
// ^T and ^U must support operator +
let inline heterogenousAdd(value1 : ^T when (^T or ^U) : (static member (+) : ^T * ^U -> ^T), value2 : ^U) =
value1 + value2
// If there are multiple constraints, use the and keyword to separate them.
type Class14<'T,'U when 'T : equality and 'U : equality> =
class end