10.3 Типы с ограниченным доступом
- 10.3.1 Типы вариантов и записей с ограниченным доступом
- 10.3.2 Сокращения типов с ограниченным доступом
- 10.3.3 Типы строк с ограниченным доступом
Объявления типов с ограниченным доступом в сигнатурах модулей, вида type t = private ..., позволяют библиотекам раскрывать некоторые, но не все аспекты реализации типа для клиентов библиотеки. В этом смысле они занимают промежуточное положение между объявлениями абстрактных типов, где никакая информация о реализации типа не раскрывается, и определениями типов данных и сокращениями типов, где все аспекты реализации типа публикуются. Объявления типов с ограниченным доступом бывают трех видов: для типов вариантов и записей (раздел 10.3.1), для сокращений типов (раздел 10.3.2) и для типов строк (раздел 10.3.3).
10.3.1 Типы вариантов и записей с ограниченным доступом
(Введено в Objective Caml 3.07)
|
Значения типа вариантов или записей, объявленных private, могут быть обычным образом деструктурированы в шаблонах сопоставления или через запись expr . field для доступа к полям записи. Однако значения этих типов не могут быть созданы напрямую с помощью применения конструктора или построения записи. Кроме того, присвоение в изменяемом поле типа записи с ограниченным доступом не разрешено.
Типичное использование типов с ограниченным доступом находится в сигнатуре экспорта модуля, для того, чтобы гарантировать, что создание значений типа с ограниченным доступом всегда происходит через функции, предоставляемые модулем, при этом позволяя сопоставление с образцом за пределами определяющего модуля. Например:
module M : sig type t = private A | B of int val a : t val b : int -> t end = struct type t = A | B of int let a = A let b n = assert (n > 0); B n end
Здесь объявление private гарантирует, что во всех значениях типа M.t аргумент конструктора B всегда является положительным целым числом.
Что касается вариативности их параметров, то типы с ограниченным доступом обрабатываются так же, как абстрактные типы. То есть, если тип с ограниченным доступом имеет параметры, их вариативность определяется явно, предваряя параметр символом ‘+’ или ‘-’; в противном случае он является инвариантным.
10.3.2 Сокращения типов с ограниченным доступом
(Введено в Objective Caml 3.11)
|
В отличие от обычного сокращения типа, сокращение типа с ограниченным доступом объявляет тип, который отличается от типа реализации typexpr. Однако разрешены преобразования из типа в typexpr. Более того, компилятор «знает» тип реализации и может использовать эти знания для выполнения оптимизаций, ориентированных на тип.
Следующий пример использует сокращение типа с ограниченным доступом для определения модуля неотрицательных целых чисел:
module N : sig type t = private int val of_int: int -> t val to_int: t -> int end = struct type t = int let of_int n = assert (n >= 0); n let to_int n = n end
Тип N.t несовместим с int, гарантируя, что неотрицательные целые числа и обычные целые числа не будут смешиваться. Однако, если x имеет тип N.t, преобразование (x :> int) является законным и возвращает базовое целое число, так же как и N.to_int x. Поддерживаются и глубокие преобразования: если l имеет тип N.t list, то преобразование (l :> int list) возвращает список базовых целых чисел, как и List.map N.to_int l, но без копирования списка l.
Обратите внимание, что преобразование ( expr :> typexpr ) на самом деле является сокращенной формой и будет работать только при наличии сокращений типов с ограниченным доступом, если ни тип expr, ни typexpr не содержат никаких переменных типа. Если они есть, вам нужно использовать полную форму ( expr : typexpr1 :> typexpr2 ), где typexpr1 — ожидаемый тип expr. Конкретно, это будет (x : N.t :> int) и (l : N.t list :> int list) для приведенных выше примеров.
10.3.3 Типы строк с ограниченным доступом
(Введено в Objective Caml 3.09)
|
Типы строк с ограниченным доступом являются сокращениями типов, где часть структуры типа остается абстрактной. В частности, typexpr в приведенном выше случае должен обозначать либо тип объекта, либо полиморфный тип вариантов с некоторыми возможными уточнениями. Если объявление с ограниченным доступом используется в интерфейсе, соответствующая реализация может либо предоставить базовую инстанцию, либо уточненный тип с ограниченным доступом.
module M : sig type c = private < x : int; .. > val o : c end = struct class c = object method x = 3 method y = 2 end let o = new c end
Это объявление делает больше, чем просто скрывает метод y, оно также делает тип c несовместимым с любым другим закрытым типом объекта, что означает, что только o будет иметь тип c. В этом смысле он ведет себя аналогично типам записей с ограниченным доступом. Однако типы строк с ограниченным доступом более гибкие с точки зрения поэтапного уточнения. Эта функция может использоваться в сочетании с функторами.
module F(X : sig type c = private < x : int; .. > end) = struct let get_x (o : X.c) = o#x end module G(X : sig type c = private < x : int; y : int; .. > end) = struct include F(X) let get_y (o : X.c) = o#y end
Полиморфный тип вариантов [t], например
type t = [ `A of int | `B of bool ]
может быть уточнен двумя способами. Определение [u] может добавить новые поля к [t], и объявление
type u = private [> t]
сохранит эти новые поля абстрактными. Создание значений типа [u] возможно с использованием известных вариантов [t], но любое сопоставление с образцом потребует обработки по умолчанию для обработки потенциальных дополнительных полей. Двойственно, объявление [u] может ограничить поля [t] с помощью абстракции: объявление
type v = private [< t > `A]
соответствует типам вариантов с ограниченным доступом. Нельзя создать значение типа с ограниченным доступом [v], кроме как с использованием явно перечисленных присутствующих конструкторов, (`A n) в этом примере; однако при сопоставлении с образцом на [v] следует предположить, что любой из конструкторов [t] может присутствовать.
Аналогично абстрактным типам, вариативность параметров типа не выводится и должна быть указана явно.
© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/privatetypes.html