Ограничения (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# поддерживает полный набор ограничений, поддерживаемый средой CLR.
В процессе определения типа некоторые ограничения автоматически выводятся компилятором.Например, если в функции используется оператор +, компилятор выводит ограничение по явному члену для типов переменных, используемых в выражении.
Следующий код иллюстрирует объявления некоторые ограничения.
// 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