约束
本主题介绍可应用于泛型类型参数的约束,以指定泛型类型或函数中类型参数的要求。
语法
type-parameter-list when constraint1 [ and constraint2]
言论
可以应用多种不同的约束来限制可在泛型类型中使用的类型。 下表列出了并描述了这些约束。
约束 | 语法 | 描述 |
---|---|---|
类型约束 | 类型参数:>类型 | 所提供的类型必须等于或派生自指定的类型,或者,如果该类型是接口,则提供的类型必须实现接口。 |
Null 约束 | type-parameter : null | 提供的类型必须支持 null 值。 这包括所有 .NET 对象类型,但不包括 F# 列表、元组、函数、类、记录或联合类型。 |
非 Null 约束 | 类型参数:非空 | 所提供的类型不得支持 null 值。 这不允许 null 批注类型以及其表示值为 null 的类型,例如选项类型或使用 AllowNullLiteral 属性定义的类型。 此泛型约束允许值类型,因为这些类型永远不能为 null。 |
显式成员约束 | [(]type-parameter [or ... or type-parameter)] : (member-signature) | 提供的至少一个类型参数必须具有具有指定签名的成员;不适用于常见用途。 为了成为显式成员约束的有效目标,成员必须在类型中明确定义或作为隐式类型扩展的一部分。 |
构造函数约束 | type-parameter : ( new : unit -> 'a ) | 提供的类型必须具有一个无参数的构造函数。 |
值类型约束 | 类型参数:结构 | 所提供的类型必须是 .NET 值类型。 |
引用类型约束 | 类型参数:非结构 | 所提供的类型必须是 .NET 引用类型。 |
枚举类型约束 | type-parameter : enum<underlying-type> | 所提供的类型必须是具有指定基础类型的枚举类型;不适用于常见用途。 |
委托约束 | type-parameter : delegate<tuple-parameter-type, return-type> | 所提供的类型必须是具有指定参数和返回值的委托类型;不适用于常见用途。 |
比较约束 | 类型参数:比较 | 所提供的类型必须支持比较。 |
相等约束 | 类型参数:相等性 | 提供的类型必须支持相等性。 |
非托管约束 | 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
// Not Null constraint
type Class4<'T when 'T : not 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