Restrições
Este tópico descreve as restrições que você pode aplicar a parâmetros de tipo genérico para especificar os requisitos de um argumento de tipo em uma função ou tipo genérico.
Sintaxe
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 essas restrições.
Constraint | Sintaxe | Descrição |
---|---|---|
Restrição de tipo | type-parameter :>type | O tipo fornecido deve ser igual ou derivado do tipo especificado ou, se o tipo for uma interface, o tipo fornecido deverá implementar a interface. |
Restrição de nulo | type-parameter : null | O tipo fornecido deve dar suporte ao literal nulo. Isso inclui todos os tipos de objeto .NET, mas não os tipos de lista, tupla, função, classe, registro ou união do F#. |
Restrição de membro explícito | [(]type-parameter [or ... or type-parameter)] : (member-signature) | Pelo menos um dos argumentos de tipo fornecidos deve ter um membro que tenha a assinatura especificada; não destinado a uso comum. Os membros devem ser definidos explicitamente no tipo ou parte de uma extensão de tipo implícito para serem destinos válidos para uma restrição de membro explícito. |
Restrição de construtor | type-parameter : ( new : unit -> 'a ) | O tipo fornecido deve ter um construtor sem parâmetro. |
Restrição de tipo de valor | type-parameter : struct | O tipo fornecido deve ser um tipo de valor .NET. |
Restrição de tipo de referência | type-parameter : not struct | O tipo fornecido deve ser um tipo de referência .NET. |
Restrição de tipo de enumeração | type-parameter : enum<underlying-type> | O tipo fornecido deve ser um tipo enumerado que tenha o tipo subjacente especificado; não destinado a uso comum. |
Restrição de delegado | type-parameter : delegate<tuple-parameter-type, return-type> | O tipo fornecido deve ser um tipo delegado que tenha os argumentos especificados e o valor retornado; não destinado a uso comum. |
Restrição de comparação | type-parameter : comparison | O tipo fornecido deve dar suporte à comparação. |
Restrição de igualdade | type-parameter : equality | O tipo fornecido deve dar suporte à igualdade. |
Restrição não gerenciada | type-parameter : unmanaged | O tipo fornecido deve ser um tipo não gerenciado. Tipos não gerenciados 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érica cujos campos são todos tipos não gerenciados. |
Você precisa adicionar uma restrição quando o código precisar 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, poderá usar qualquer um dos métodos dessa classe na função ou tipo genérico.
Às vezes, a especificação de restrições é necessária ao gravar parâmetros de tipo explicitamente, pois sem uma restrição, o compilador não tem como verificar se os recursos que você está usando estarão disponíveis em qualquer tipo que possa ser fornecido em tempo de execução para o parâmetro de tipo.
As restrições mais comuns usadas no código F# são restrições de tipo que especificam classes base ou interfaces. As outras restrições são usadas pela biblioteca de F# para implementar determinadas funcionalidades, como a restrição de membro explícito, que é usada para implementar a sobrecarga de operador para operadores aritméticos, ou são fornecidas principalmente porque F# dá suporte ao conjunto completo de restrições com suporte do Common Language Runtime.
Durante o processo de inferência de tipo, algumas restrições são inferidas automaticamente pelo compilador. Por exemplo, se você usar o operador +
em uma função, o compilador inferirá uma restrição de membro explícita em tipos de variáveis que são usados na expressão.
O seguinte código 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 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