Contraintes (F#)
Cette rubrique décrit les contraintes que vous pouvez appliquer aux paramètres de type générique pour spécifier les spécifications pour un argument de type dans un type ou une fonction générique.
type-parameter-list when constraint1 [ and constraint2]
Notes
Vous pouvez appliquer différentes contraintes pour limiter les types pouvant être utilisés dans un type générique. Le tableau suivant répertorie et décrit ces contraintes.
Contrainte |
Syntaxe |
Description |
---|---|---|
Contrainte de type |
type-parameter :> type |
Le type fourni doit être égal au type spécifié ou dérivé de celui-ci. Si le type est une interface, le type fourni doit implémenter l'interface. |
Contrainte Null |
type-parameter : null |
Le type fourni doit prendre en charge le littéral Null. Ceci inclut tous les types d'objet .NET, mais pas les types de liste, de tuple, de fonction, de classe, d'enregistrement ou d'union F#. |
Contrainte de membre explicite |
[(]type-parameter[or ... ou type-parameter)] : (member-signature) |
Au moins l'un des arguments de type fourni doit avoir un membre qui a la signature spécifiée (non conçu pour une utilisation courante). |
Contrainte de constructeur |
type-parameter : ( new : unit -> 'a ) |
Le type fourni doit avoir un constructeur par défaut. |
Contrainte de type valeur |
: struct |
Le type fourni doit être un type valeur .NET. |
Contrainte de type référence |
: not struct |
Le type fourni doit être un type référence .NET. |
Contrainte de type d'énumération |
: enum<underlying-type> |
Le type fourni doit être un type énuméré qui a le type sous-jacent spécifié (non conçu pour une utilisation courante). |
Contrainte de délégué |
: delegate<tuple-parameter-type, return-type> |
Le type fourni doit être un type délégué qui a les arguments et la valeur de retour spécifiés (non conçu pour une utilisation courante). |
Contrainte de comparaison |
: comparison |
Le type fourni doit prendre en charge la comparaison. |
Contrainte d'égalité |
: equality |
Le type fourni doit prendre en charge l'égalité. |
Contrainte non managée |
: unmanaged |
Le type fourni doit être un type non managé. Les types non managés sont soit certains types primitifs (sbyte, byte, char, nativeint, unativeint, float32, float, int16, uint16, int32, uint32, int64, uint64 ou decimal), soit des types d'énumération, nativeptr<_>, soit une structure non générique dont les champs sont tous des types non managés. |
Vous devez ajouter une contrainte lorsque votre code doit utiliser une fonctionnalité qui est disponible sur le type de contrainte, mais pas sur les types en général. Par exemple, si vous utilisez la contrainte de type pour spécifier un type de classe, vous pouvez utiliser n'importe laquelle des méthodes de cette classe dans la fonction ou le type générique.
La spécification de contraintes est parfois obligatoire lors de l'écriture explicite de paramètres de type ; en effet, sans contrainte, le compilateur n'a aucun moyen de vérifier que les fonctionnalités que vous utilisez seront disponibles sur chaque type pouvant être fourni au moment de l'exécution pour le paramètre de type.
Les contraintes utilisées le plus couramment dans le code F# sont les contraintes de type qui spécifient des classes ou des interfaces de base. Les autres contraintes sont soit utilisées par la bibliothèque F# pour implémenter certaines fonctionnalités, par exemple la contrainte de membre explicite qui est utilisée pour implémenter la surcharge d'opérateur pour les opérateurs arithmétiques, soit fournies principalement parce que F# prend en charge le jeu complet de contraintes pris en charge par le common language runtime.
Au cours du processus d'inférence de type, certaines contraintes sont déduites automatiquement par le compilateur. Par exemple, si vous utilisez l'opérateur + dans une fonction, le compilateur déduit une contrainte de membre explicite sur les types de variable utilisés dans l'expression.
Le code suivant illustre quelques déclarations de contrainte.
// 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