Restrições
Este tópico descreve as restrições que você pode aplicar a parâmetros de tipo genéricos para especificar os requisitos para um argumento de tipo em um tipo ou função genéricos.
Sintaxe
type-parameter-list when constraint1 [ and constraint2]
Observações
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.
Restrição | Sintaxe | Description |
---|---|---|
Restrição de tipo | type-parameter :>tipo | O tipo fornecido deve ser igual ou derivado do tipo especificado ou, se o tipo for 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 os tipos de lista, tupla, função, classe, registro ou união F#. |
Restrição explícita de membro | [(]tipo-parâmetro [ou ... ou tipo-parâmetro)] : (membro-assinatura) | Pelo menos um dos argumentos de tipo fornecidos deve ter um membro que tenha a assinatura especificada; não se destina a uso comum. Os membros devem ser explicitamente definidos no tipo ou parte de uma extensão de tipo implícita para serem destinos válidos para uma restrição explícita de membro. |
Restrição do construtor | tipo-parâmetro : ( novo : unidade -> 'a ) | O tipo fornecido deve ter um construtor sem parâmetros. |
Restrição de tipo de valor | tipo-parâmetro : struct | O tipo fornecido deve ser um tipo de valor .NET. |
Restrição de tipo de referência | tipo-parâmetro : não struct | O tipo fornecido deve ser um tipo de referência .NET. |
Restrição de tipo de enumeração | tipo-parâmetro : enum<underlying-type> | O tipo fornecido deve ser um tipo enumerado que tenha o tipo subjacente especificado; não se destina a uso comum. |
Delegar restrição | type-parameter : delegar<tuple-parameter-type, return-type> | O tipo fornecido deve ser um tipo delegado que tenha os argumentos especificados e o valor de retorno; não se destina a uso comum. |
Restrição de comparação | tipo-parâmetro : comparação | O tipo fornecido deve suportar a comparação. |
Restrição de igualdade | tipo-parâmetro : igualdade | O tipo fornecido deve apoiar a igualdade. |
Restrição não gerenciada | type-parameter : não gerenciado | O tipo fornecido deve ser um tipo não gerenciado. Tipos não gerenciados são certos tipos primitivos (sbyte , byte , , char nativeint , unativeint , float32 , float , uint16 int64 int16 uint32 uint64 int32 ou decimal ), tipos de enumeração, nativeptr<_> ou uma estrutura não genérica cujos campos são todos os tipos não gerenciados. |
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 nos 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.
Especificar restrições às vezes é necessário ao escrever parâmetros de tipo explicitamente, porque 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 type.
As restrições mais comuns que você usa 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 F# para implementar determinadas funcionalidades, como a restrição de membro explícito, que é usada para implementar a sobrecarga do operador para operadores aritméticos, ou são fornecidas principalmente porque o F# suporta o conjunto completo de restrições que é suportado pelo 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 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 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