Rascal读取含重载构造函数的JSON报错,如何实现JSON读写?
带可选字段的Rascal Block类型JSON读写可行方案
原Rascal代码
import lang::json::IO; data Field = field(map[str, str]); data Block = null() | block(str \type) | block(str \type, str id) | block(str \type, Block next) | block(str \type, Field field, Input input, Block next); data Input = input(map[str, Block]); writeJSON(|file:///rascal/block.json|, block("type","sdlkfjl")); readJSON(#Block, |file:///rascal/block.json|);
执行报错信息
rascal>readJSON(#Block, |file:///rascal/block.json|); |std:///lang/json/IO.rsc|(976,2999,<32,0>,<60,179>): IO("Overloading of constructor names is not supported (Block):$.block") at *** somewhere ***(|std:///lang/json/IO.rsc|(976,2999,<32,0>,<60,179>)) at readJSON(|std:///lang/json/IO.rsc|(3968,5,<60,172>,<60,177>)ok rascal>
可行解决方案
报错核心原因是Rascal的lang::json::IO库不支持同名构造器重载,以下是三种可行解决思路:
方案一:单一构造函数+可选参数
将所有可选字段整合到一个构造函数中,通过默认值实现可选逻辑,彻底避免重载冲突:
import lang::json::IO; data Field = field(map[str, str]); data Block = block(str type, str id = "", Block next = null(), Field field = null(), Input input = null()) | null(); data Input = input(map[str, Block]); // 写入时仅传递必要参数,其余使用默认值 writeJSON(|file:///rascal/block.json|, block("type", "sdlkfjl")); // 读取操作可正常执行 Block result = readJSON(#Block, |file:///rascal/block.json|);
这种方式最简洁,符合Rascal数据类型设计的最佳实践,JSON序列化后会自动只保留非默认值的字段。
方案二:为不同变体使用唯一构造函数名
给每个Block变体分配不同的构造函数名称,消除同名重载问题:
import lang::json::IO; data Field = field(map[str, str]); data Block = null() | blockTypeOnly(str type) | blockWithId(str type, str id) | blockWithNext(str type, Block next) | blockFull(str type, Field field, Input input, Block next); data Input = input(map[str, Block]); // 写入对应变体实例 writeJSON(|file:///rascal/block.json|, blockTypeOnly("type", "sdlkfjl")); // 读取操作可正常执行 Block result = readJSON(#Block, |file:///rascal/block.json|);
此方案保留了原有的变体区分逻辑,JSON会以构造函数名作为标识字段,便于手动查看和调试结构。
方案三:自定义序列化/反序列化函数
手动实现Block与JSON的转换逻辑,完全控制读写过程,适合复杂场景:
import lang::json::IO; import lang::json::Value; data Field = field(map[str, str]); data Block = null() | block(str type) | block(str type, str id) | block(str type, Block next) | block(str type, Field field, Input input, Block next); data Input = input(map[str, Block]); // 自定义序列化:Block转JSON Value Value blockToJson(Block b) { switch(b) { case null(): return object("variant": "null"); case block(str t): return object("variant": "block", "type": t); case block(str t, str id): return object("variant": "block_with_id", "type": t, "id": id); case block(str t, Block next): return object("variant": "block_with_next", "type": t, "next": blockToJson(next)); case block(str t, Field field, Input input, Block next): return object( "variant": "block_full", "type": t, "field": object(field.map), "input": object(input.map), "next": blockToJson(next) ); } } // 自定义反序列化:JSON Value转Block Block jsonToBlock(Value v) { map[str, Value] obj = v; switch(obj["variant"].str) { case "null": return null(); case "block": return block(obj["type"].str); case "block_with_id": return block(obj["type"].str, obj["id"].str); case "block_with_next": return block(obj["type"].str, jsonToBlock(obj["next"])); case "block_full": return block( obj["type"].str, field(obj["field"].map[str, str]), input(obj["input"].map[str, Block]), jsonToBlock(obj["next"]) ); default: throw IO("Unknown Block variant"); } } // 写入时先转换为JSON Value writeJSON(|file:///rascal/block.json|, blockToJson(block("type", "sdlkfjl"))); // 读取时先读为Value再转换为Block Block result = jsonToBlock(readJSON(|file:///rascal/block.json|));
该方案灵活性最高,适合需要定制JSON格式或处理复杂嵌套结构的场景,但需要手动维护转换逻辑的一致性。
内容的提问来源于stack exchange,提问作者Koen Van Wijk
相关产品推荐
相关产品推荐

