Глава 12 Расширения языка
3 Типы с ограниченным доступом
- 3.1 Типы вариантов и записей с ограниченным доступом
- 3.2 Сокращения типов с ограниченным доступом
- 3.3 Типы строк с ограниченным доступом
Объявления типов с ограниченным доступом в сигнатурах модулей, в форме type t = private ..., позволяют библиотекам раскрывать некоторые, но не все аспекты реализации типа для клиентов библиотеки. В этом отношении они занимают среднее положение между объявлениями абстрактных типов, где никакая информация о реализации типа не раскрывается, и определениями типов данных и сокращениями типов, где все аспекты реализации типа публикуются. Объявления типов с ограниченным доступом бывают трех видов: для типов вариантов и записей (раздел 12.3.1), для сокращений типов (раздел 12.3.2) и для типов строк (раздел 12.3.3).
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 всегда является положительным целым числом.
Что касается вариативности их параметров, типы с ограниченным доступом обрабатываются как абстрактные типы. То есть, если у типа с ограниченным доступом есть параметры, их вариативность определяется явно с помощью префикса ‘+’ или ‘-’; в противном случае вариативность неизменна.
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).
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-2024 INRIA.
https://ocaml.org/manual/5.2/privatetypes.html