约束
此主题介绍可应用于泛型类型参数的约束,这些约束指定对泛型类型或函数中类型参数的要求。
语法
type-parameter-list when constraint1 [ and constraint2]
备注
有几种不同的约束可用于限制可在泛型类型中使用的类型。 下表列出了这些约束并对它们作出说明。
约束 | 语法 | 说明 |
---|---|---|
类型约束 | type-parameter :>type | 提供的类型必须是或派生自指定的类型,或如果该类型是接口,则提供的类型必须实现该接口。 |
Null 约束 | type-parameter : null | 提供的类型必须支持 null 文本。 这包括所有 .NET 对象类型,但不包括 F# 列表、元组、函数、类、记录或联合类型。 |
显式成员约束 | [(]type-parameter [or ... or type-parameter)] : (member-signature) | 提供的至少一个类型参数必须包含具有指定签名的成员;不适用于常规用途。 成员必须在类型上显式定义或是隐式类型扩展的一部分,才能成为显式成员约束的有效目标。 |
构造函数约束 | type-parameter : ( new : unit -> 'a ) | 提供的类型必须具有一个无参数的构造函数。 |
值类型约束 | type-parameter:结构 | 提供的类型必须是 .NET 值类型。 |
引用类型约束 | type-parameter:非结构 | 提供的类型必须是 .NET 引用类型。 |
枚举类型约束 | type-parameter:enum<underlying-type> | 提供的类型必须是具有指定基础类型的枚举类型;不用于常规用途。 |
委托约束 | type-parameter:delegate<tuple-parameter-type、return-type> | 提供的类型必须是具有指定参数和返回值的委托类型;不用于常规用途。 |
比较约束 | type-parameter:comparison | 提供的类型必须支持比较。 |
相等约束 | type-parameter:equality | 提供的类型必须支持相等性。 |
非托管约束 | type-parameter:unmanaged | 提供的类型必须是非托管类型。 非托管类型可以是某些基本类型(sbyte 、byte 、char 、nativeint 、unativeint 、float32 、float 、int16 、uint16 、int32 、uint32 、int64 、uint64 或 decimal )、枚举类型、nativeptr<_> 或是字段均为非托管类型的非泛型结构。 |
当代码需要使用在约束类型上可用但通常在类型上不可用的功能时,则需要添加约束。 例如,如果使用类型约束来指定类类型,可以在泛型函数或类型中使用该类的任何一种方法。
在显式编写类型参数时,有时需要指定约束,因为如果没有约束,编译器无法验证你使用的功能是否可用于在运行时可能为类型参数提供的任何类型。
在 F# 代码中使用的最常见约束是指定基类或接口的类型约束。 其他约束要么由 F# 库用于实现某些功能,例如显式成员约束(用于实现算术运算符的运算符重载),要么主要由于 F# 支持公共语言运行库支持的一整套约束而被提供。
在类型推理过程中,编译器会自动推断某些约束。 例如,如果在函数 +
中使用该运算符,编译器将推断表达式中使用的变量类型的显式成员约束。
下面的代码演示了一些约束声明:
// 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