簡體   English   中英

在 Reasonml 中迭代記錄鍵和值的最佳實踐是什么?

[英]What is the best practice of iterating record keys and values in Reasonml?

我是 ReasonML 的新手,但我閱讀了大部分官方文檔。 我可以為此進行隨意的試驗和錯誤,但由於我現在需要在 ReasonML 中編寫代碼,我想知道迭代原因記錄類型的鍵和值的最佳實踐。

也許我不理解問題或用例。 但據我所知,沒有辦法遍歷記錄的鍵/值對。 您可能想要使用不同的數據模型:

有了記錄,所有的鍵和值類型都是已知的,因此您只需編寫代碼來處理每一個,無需迭代。

我完全同意@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.Obj API,因為它要么不合理,要么非常不切實際。 為了證明這一點,讓我們嘗試自己制作。

我們可以輕松地編寫我們自己的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 中推斷的string | int類型。

為了解決這個問題,我們可以使值成為抽象類型並使用Js.Types.classify來安全地獲取實際的底層數據類型,類似於在 JavaScript 中使用typeof

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 文檔已被刪除(是的,現在一團糟,我知道。希望是這樣)最終會改進。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM