为啥 jsonDecode 返回一个不可转换为 Map<String, Map<String, String>> 的值?

Posted

技术标签:

【中文标题】为啥 jsonDecode 返回一个不可转换为 Map<String, Map<String, String>> 的值?【英文标题】:Why does jsonDecode return a value that is uncastable to Map<String, Map<String, String>>?为什么 jsonDecode 返回一个不可转换为 Map<String, Map<String, String>> 的值? 【发布时间】:2020-11-12 02:09:22 【问题描述】:

我正在编写一个语言工具。我有一个看起来像这样的languages.json 文件:


    "paradigms": 
        "test paradigm": 
            "1sg": "me",
            "2sg.gen": "lo",
            "3pl.acc": "tven"
        
    

(或者,至少这是相关部分)

然后,在我的主要 dart 文件中,我尝试打开 JSON 文件的一部分并将其解析为地图:

void main() async 
    var langjson = jsonDecode(await File('resource/languages.json').readAsString());
    var paradigms = Map<String, Map<String, String>>.from(langjson['paradigms']);

现在飞镖告诉我_TypeError (type '_InternalLinkedHashMap&lt;String, dynamic&gt;' is not a subtype of type 'Map&lt;String, String&gt;')。好的,我知道如果我不强制转换它,那么 paradigms 无论如何都会是那种奇怪的类型,但是我无法将它传递给某个类,这意味着我必须制作类型这些成员也是动态的,而且看起来有点丑(我已经测试过了,它有效)。难道没有办法从jsonDecode 中简单地得到Map 吗?我认为这就是它应该如何工作的方式?

【问题讨论】:

【参考方案1】:

JSON解析的静态返回类型为dynamic,因为它可以是map、list、number、string、boolean或null。出于同样的原因,如果它是一个地图,它就是一个Map&lt;String, dynamic&gt;,因为值可以是上述任何一个。

在您的情况下,您碰巧知道结果始终是一个映射,并且该映射的值又是映射,并且这些映射的值都是字符串。因此,数据将匹配 Map&lt;String, Map&lt;String, String&gt;&gt;,但 JSON 解码器不会提前知道这一点,因此它会构建一个包含 Map&lt;String, dynamic&gt; 值的 Map&lt;String, dynamic&gt;

Dart 将泛型类型具体化,因此仅包含字符串的Map&lt;String, dynamic&gt;Map&lt;String, String&gt; 不同。您可以为前者添加一个数字值,而不是为后者添加一个数字值,因此它们是不同的。

要将您的数据映射转换为 Map&lt;String, String&gt; 类型的东西,您可以急切地这样做:

var paradigms = langJson["paradigms"].map(value: (k, v) => MapEntry(k, v as String));

或懒惰:

var paradigms = langJson["paradigms"].cast<String, String>();

前者立即检查所有值,并创建一个新的地图对象。后者包装原始地图对象,并在每次访问时检查该值是否为String

【讨论】:

【参考方案2】:

_InternalLinkedHashMap Map 的子类型,您可以在此答案here 中阅读。您的代码的问题是您指定不兼容的值存储在Map 中。你说&lt;String, String&gt;,其实只能是&lt;String, dynamic&gt;。改变 Map&lt;String, Map&lt;String, dynamic&gt;&gt; 会解决你的问题。

此外,正如您在链接的答案中看到的那样,完全不需要使用 from 构造函数来创建新的 Map,因为 jsonDecode 已经返回了您尝试创建的确切数据类型。

【讨论】:

以上是关于为啥 jsonDecode 返回一个不可转换为 Map<String, Map<String, String>> 的值?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 JSONDecoder.decode 方法时没有调用 Decodable 的 init 方法?

为啥 JsonDecoder 在尝试解析邮递员网址但处理其他网址时出现错误?

Schema graphql 错误给出“不能为不可为空的字段 Organisation.id 返回 null”为啥?

如何处理 JSONDecoder 中的空日期字符串

Flutter json 和 对象之间的转换

Flutter json 和 对象之间的转换