约束 (F#)
本主题介绍一些约束,您可以将这些约束应用于泛型类型参数,以指定对泛型类型或函数中的类型参数的要求。
type-parameter-list when constraint1 [ and constraint2]
备注
可以应用若干个不同的约束来限制可在泛型类型中使用的类型。 下表列出了这些约束并提供了相关说明。
约束 |
语法 |
描述 |
---|---|---|
类型约束 |
type-parameter :> type |
提供的类型必须与指定的类型相同或派生自指定的类型;如果指定的类型是一个接口,则提供的类型必须实现此接口。 |
Null 约束 |
type-parameter : null |
提供的类型必须支持 null 文本。 这包括所有 .NET 对象类型,但不包括 F# 列表、元组、函数、类、记录或联合类型。 |
显式成员约束 |
[(]type-parameter [或… 或 type-parameter)]:(member-signature) |
所提供的类型参数中至少有一个必须具有包含指定签名的成员;通常不会用到此类约束。 |
构造函数约束 |
type-parameter : ( new : unit -> 'a ) |
提供的类必须具有默认构造函数。 |
值类型约束 |
: struct |
提供的类型必须是 .NET 值类型。 |
引用类型约束 |
: not struct |
提供的类型必须是 .NET 引用类型。 |
枚举类型约束 |
: enum<underlying-type> |
提供的类型必须是具有指定的基础类型的枚举类型;通常不会用到此类约束。 |
委托约束 |
: delegate<tuple-parameter-type, return-type> |
提供的类型必须是具有指定的参数和返回值的委托类型;通常不会用到此类约束。 |
比较约束 |
: comparison |
提供的类型必须支持比较。 |
相等性约束 |
: equality |
提供的类型必须支持相等性。 |
非托管约束 |
: 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 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