有没有办法使用 bs-json 对大于 32 位的整数值进行编码?

Is there a way to encode integer values that are larger than 32 bits using bs-json?

我一直在使用字符串来表示解码后的 JSON 大于 32 位的整数。似乎 string_of_int 能够处理大整数输入。所以一个解码器,写成(在 Json.Decode 命名空间):

id: json |> field("id", int) |> string_of_int,  /* 'id' is string */

正在成功处理至少 37 位的整数。

另一方面,事实证明编码对我来说很麻烦。远程服务器不接受字符串表示,并期待 int64。是否可以让 bs-json 支持 int64 类型?我希望这样的东西可以工作:

type myData = { id: int64 };

let encodeMyData = (data:myData) => Json.Encode.(object_([("id", int64(myData.id)]))

不得不推出自己的编码器并不像解码器那么可怕,但是......我宁愿不这样做。

你没有具体说出编码有什么问题。 int 编码器实际上除了改变类型什么都不做,相信 int 值实际上是有效的。所以我假设是 int_of_string 操作导致了问题。但这引出了一个问题,如果你能成功地将它解码为 int,为什么还要将它转换为 string

这里的根本问题是 JavaScript 没有 64 位整数。 max safe integer is 253 - 1. JavaScript doesn't actually have integers at all, only floats, which can represent a certain range of integers, but can't efficiently do integer arithmetic unless they're converted to either 32-bit or 64-bit ints. And so for whatever reason, probably consistent overflow handling, it was decided in the EcmaScript specification 二进制按位运算应该对 32 位整数进行运算。因此,这为内部 32 位表示、创建 32 位整数的符号以及优化整数算法的可能性打开了可能性。

所以对于你的问题:

Would it be "safe" to just add external int64 : int64 -> Js.Json.t = "%identity" to the encoder files?

不,因为 JavaScript 中没有 64 位整数表示,int64 值表示为两个 Number 的数组,我相信,但这也是一个内部实现细节可能会发生变化。仅将其转换为 Js.Json.t 不会产生您期望的结果。

那么可以做什么呢?

我建议使用 float。在大多数方面,这将与 JavaScript 数字完全一样,让您可以访问其全部范围。

或者您可以使用 nativeint,它的行为应该类似于 floats 除了除法,结果被截断为 32 位整数。

最后,您还可以实现自己的 int_of_string,通过直接使用几个轻量级 JavaScript 函数来创建技术上超出范围的 int,但我不会真的不推荐这样做:

let bad_int_of_string = str => 
  str |> Js.Float.fromString |> Js.Math.floor_int;