0

我一直在使用字符串来表示大于 32 位的解码 JSON 整数。似乎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)]))

不得不滚动我自己的编码器并不像解码器那样强大,但是......我宁愿不这样做。

4

1 回答 1

0

您没有确切地说出编码有什么问题。编码器int实际上除了更改类型之外什么都不做,相信该int值实际上是有效的。所以我认为这int_of_string是导致问题的操作。但这引出了一个问题,如果您可以成功将其解码为 ,那么您int为什么还要将其转换为string

这里的根本问题是 JavaScript 没有 64 位整数。最大安全整数是 2 53 - 1。JavaScript 实际上根本没有整数,只有floats,它可以表示一定范围的整数,但不能有效地进行整数运算,除非将它们转换为 32 位或 64 位int的。因此,无论出于何种原因,可能是一致的溢出处理,在EcmaScript 规范中决定二进制按位运算应该对 32 位整数进行操作。因此,这为内部 32 位表示、创建 32 位整数的符号以及优化整数运算的可能性打开了可能性。

所以对于你的问题:

将外部 int64 : int64 -> Js.Json.t = "%identity" 添加到编码器文件中是否“安全”?

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

那么你能做什么呢?

我建议使用float. 在大多数方面,它的行为与 JavaScript 数字完全一样,让您可以访问它的全部范围。

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

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

let bad_int_of_string = str => 
  str |> Js.Float.fromString |> Js.Math.floor_int;
于 2021-03-15T08:24:56.700 回答