Как мне написать универсальную функцию для обработки нескольких типов записей в ReScript?
Учитывая следующий надуманный пример, можно ли написать
get
функция, которая может обрабатывать любую запись с
a
свойство?
type type_one = {a: int}
type type_two = {a: int, b: int}
let example_one = {a: 1}
let example_two = {a: 1, b: 2}
let get = record => record.a
Js.log(get(example_one)) // notice the error here
Js.log(get(example_two))
Если нет, возможно ли это с объектом? Или как лучше всего справиться с этой ситуацией?
1 ответ
Это не. Поскольку записи являются номинальными (в отличие от структурно) типизированными, невозможно указать «любую запись с полем». Следовательно
get
будет выведен последний тип, который компилятор видел с
a
поле, которое
type_two
.
Однако существует тип объекта, который является структурным с подтипами, что позволяет это:
type type_one = {"a": int}
type type_two = {"a": int, "b": int}
let example_one = {"a": 1}
let example_two = {"a": 1, "b": 2}
let get = (record) => record["a"]
Js.log(get(example_one)) // notice no error here
Js.log(get(example_two))
Но помните, что есть некоторые компромиссы с использованием объектов вместо записей, например, невозможность деструктурировать их в шаблонах.
Также, в качестве примечания, на некоторых языках это может быть выполнено другим способом - с помощью специального полиморфизма, путем явного определения общего интерфейса и реализаций, прикрепленных к определенным типам (называемых классами типов в Haskell, чертами в Rust). Rescript и OCaml, к сожалению, в настоящее время также не поддерживают это, хотя есть предложение для OCaml в виде модульных имплицитов. Однако в OCaml вы по-прежнему можете определять общий интерфейс и реализации с помощью модулей и передавать их явно . Rescript также поддерживает типы модулей и модули, но, к сожалению, он, похоже, не раскрывает первоклассные модули, то есть передает модули как значения. Так что это тоже похоже на запрет.