Как лучше всего повторять ключи и значения записей в Reasonml?

Я новичок в ReasonML, но прочитал большинство официальных документов. Я мог бы пройти через случайные пробы и ошибки для этого, но поскольку мне нужно писать коды в ReasonML прямо сейчас, я хотел бы знать лучшие практики итерации ключей и значений типов записей причин.

2 ответа

Решение

Я полностью согласен с @Shawn, что вам следует использовать более подходящую структуру данных. Например, список кортежей - это хороший и простой способ передать определенный пользователем набор однородных пар ключ / значение:

       fooOnThis([
  ("test1", ["a", "b", "c"]),
  ("test2", ["c"]),
])

Если вам нужны разнородные данные, я бы предложил использовать вариант для указания типа данных:

       type data =
  | String(string)
  | KvPairs(list((string, data)));

fooOnThis([
  ("test1", [String("a"), String("b"), String("c")]),
  ("test2", [String("c"), KvPairs([("innerTest", "d")])]),
])

В качестве альтернативы вы можете использовать объекты вместо записей, что похоже на то, что вы действительно хотите.

Для записи требуется предварительно определенный тип записи:

       type record = {
  foo: int,
  bar: string,
};

и вот как вы их строите:

       let value = {
  foo: 42,
  bar: "baz",
};

С другой стороны, объекты структурно типизированы, то есть им не требуется заранее определенный тип, и вы создаете их немного иначе:

       let value
  : {. "foo": int, "bar": string }
  = {"foo": 42, "bar": "baz"};

Обратите внимание, что ключи - это строки.

С объектами вы можете использовать Js.Obj.keys чтобы получить ключи:

       let keys = Js.Obj.keys(value); // returns [|"foo", "bar"|]

Теперь проблема заключается в получении значений. Здесь нет Js.ObjAPI для получения значений или записей, потому что это было бы либо нецелесообразно, либо очень непрактично. Чтобы продемонстрировать это, попробуем сделать это сами.

Мы легко можем написать собственную привязку к Object.entries:

       [@bs.val] external entries: Js.t({..}) => array((string, _)) = "Object.entries";

entries вот функция, которая принимает любой объект и возвращает массив кортежей с stringключи и значения типа, которые будут выводиться в зависимости от того, как мы их используем. Это небезопасно, потому что мы не знаем, каковы фактические типы значений, и не особенно практично, поскольку они будут однородно типизированы. Например:

       let fields = entries({"foo": 42, "bar": "baz"});

// This will infer the value's type as an `int`
switch (fields) {
| [|("foo", value), _|] => value + 2
| _ => 0
};

// This will infer the value's type as an `string`, and yield a type error
// because `fields` can't be typed to hold both `int`s and `string`s
switch (fields) {
| [|("foo", value), _|] => value ++ "2"
| _ => ""
};

Вы можете использовать любой из этих switch выражения (с неожиданными результатами и возможными сбоями во время выполнения), но не оба вместе, поскольку нет распакованного string | int тип, который будет выведен в Reason.

Чтобы обойти это, мы можем сделать значение абстрактным типом и использовать Js.Types.classify чтобы безопасно получить фактический базовый тип данных, аналогично использованию typeof в JavaScript:

       type value;

[@bs.val] external entries: Js.t({..}) => array((string, value)) = "Object.entries";

let fields = entries({"foo": 42, "bar": "baz"});

switch (fields) {
| [|("foo", value), _|] =>
  switch (Js.Types.classify(value)) {
  | JSString(str) => str
  | JSNumber(number) => Js.Float.toString(number)
  | _ => "unknown"
  }
| _ => "unknown"
};

Это совершенно безопасно, но, как видите, не очень практично.

Наконец, мы можем немного изменить это, чтобы безопасно использовать его также и с записями, полагаясь на тот факт, что записи внутренне представлены как объекты JavaScript. Все, что нам нужно сделать, это не ограничивать entries к объектам:

       [@bs.val] external entries: 'a => array((string, value)) = "Object.entries";

let fields = keys({foo: 42, bar: 24}); // returns [|("foo", 42), ("bar", 24)|]

Это по-прежнему безопасно, потому что все значения являются объектами в JavaScript, и мы не делаем никаких предположений о типе значений. Если мы попытаемся использовать это с примитивным типом, мы просто получим пустой массив, а если мы попытаемся использовать его с массивом, мы получим индексы в качестве ключей.

Но поскольку записи должны быть предварительно определены, это не будет очень полезно. Итак, все это говорит о том, что я все же предлагаю перейти к списку кортежей.

Примечание: здесь используется синтаксис ReasonML, поскольку это то, о чем вы просили, но относится к документации ReScript, в которой используется немного другой синтаксис ReScript, поскольку документация BuckleScript была удалена (да, сейчас беспорядок, я знаю. Надеюсь, что это '' со временем улучшу.)

Возможно, я не понимаю вопрос или вариант использования. Но, насколько мне известно, нет возможности перебирать пары ключ / значение в записи. Вы можете использовать другую модель данных:

С помощью записи известны все ключи и типы значений, поэтому вы можете просто написать код для обработки каждого из них, без необходимости повторения.

Другие вопросы по тегам