>代数数据类型是一种准确描述数据的方法。
当涉及到JSON时,产品类型没有问题,即每个结构都逐个列出属于它们的道具。
然而,目前尚不清楚如何处理暗示一组道具或另一组道具的和类型,但不能同时暗示两者或它们的混合(除非它们有一些相似之处)。
所以
- 如何在 JSON 中表示总和类型?
- 如何区分同样可能的情况?
以以下变体类型为例。
data Tree = Empty
| Leaf Int
| Node Tree Tree
在 JSON 中,您可以使用以下三种形式来指定三种变体。
Variant | JSON
--------+---------------
Empty | null
--------+---------------
Leaf | {
| "leaf": 7
| }
--------+---------------
Node | {
| "node": [
| <tree>,
| <tree>
| ]
| }
基本上,使用具有单个键值对的 JSON 对象,其中键是所选变体。
也许使用具有value
和tag
属性的对象表示法? 例如:
{
"someVariant": {
"value": 25,
"tag": "currentFormOfTheVariant"
}
}
对象和特殊格式的字符串基本上是您在 JSON 中自描述数据类型的唯一真正选择。
让我们看看Cereal在C++会做什么。
std::ostringstream oss;
{
cereal::JSONOutputArchive oa{oss};
std::variant<double, std::string> v1{std::string{"hello"}};
std::variant<double, std::string> v2{3.14};
oa << cereal::make_nvp("v1", v1);
oa << cereal::make_nvp("v2", v2);
}
std::cout << oss.str() << std::endl;
https://godbolt.org/z/fx1zcYM84
输出:
{
"v1": {
"index": 1,
"data": "hello"
},
"v2": {
"index": 0,
"data": 3.14
}
}
当然,它会保存变体的替代索引,然后保存实际值。读取(反序列化)期间需要索引才能知道如何读取以下字段。如果没有该"索引"信息,则需要做大量工作来解析以下字段并通过反复试验推断类型信息,并且有时仍然无法解决歧义。