# 数据格式 看到这里,你一定对JSON中的对象具有一定的了解了,但是,我们依旧尚未关注对象中字段的值都允许什么样的类型。我们将目光看向上面的“缩进示例”所描述的文件。如果记忆力不错的话,你一定还记得我们说过这是附加包的清单文件。我们就再次来以这个清单文件为例,学习JSON中的值所允许的数据类型,或者说,数据格式。 ## 数字 ```json { "format_version": 2, "header": { }, "modules": [ ] } ``` JSON中的值允许使用**数字**(**Number**),例如上述的`"format_version": 2`中的值`2`。当然,数字未必是整数,JSON中允许**整数**(**Integer**,**int**)和**浮点数**(**Floating Number**,**float**)两种数字形式。浮点数即我们平常所说的“小数”,或者说“实数”,不过虽然可能会被称为“实数”或“实型”,但是事实上显然是只能接受“有理数”的输入,或者更准确地说,有限小数的输入。以下示例都属于数字数据格式: ```json { "height": 170, "weight": 60.5, "chest": 90.95, "waist": 62.05, "hip": 96.05 } ``` ## 对象 ```json { "format_version": 2, "header": { "description": "resourcePack.vanilla.description", "name": "resourcePack.vanilla.name", "uuid": "0575c61f-a5da-4b7f-9961-ffda2908861e", "version": [0, 0, 1], "min_engine_version": [1, 13, 0] }, "modules": [ ] } ``` JSON中字段的值也可以是一个完整的对象,就比如这里`"header"`字段的值即是一个对象,这个对象中又含有`description"`等五个新的字段。对象常用来表达属性之间的包含关系。最外面的对象,在上述示例中也就是第一行和最后一行的花括号所括住的对象,被我们称为该JSON的**根对象**(**Root Object**)。 ## 字符串 ```json { "format_version": 2, "header": { "description": "resourcePack.vanilla.description", "name": "resourcePack.vanilla.name", "uuid": "0575c61f-a5da-4b7f-9961-ffda2908861e", "version": [0, 0, 1], "min_engine_version": [1, 13, 0] }, "modules": [ ] } ``` 除了数字和对象之外,JSON中也有一种用于表示“一段文本”的数据格式,那便是**字符串**(**String**)。顾名思义,字符串就是一列字符“串”在一起,即“一段文本”,为了能够使计算机正确解析字符串,正确“认识到”这是一个字符串,我们需要使用**英文直引号**`"`将字符串的两侧括住。以下便是一些字符串的示例: ```json { "name": "小明", "gender": "", "height": "170cm", "weight": "60.5kg", "chest": "90.95cm", "waist": "62.05cm", "hip": "96.05cm" } ``` 由于小明是我虚构的人物,而我并不想擅自假定小明的性别,所以我在`"gender"`字段里留了空,相邻的两个引号`""`也是一种字符串,这种字符串被称为**空字符串**(**Empty String**)。我们可以看到,除了字段的值可以是字符串之外, 字段的键也都是使用英文直引号`"`括起来的形式。虽然并不建议这么理解,但是如果你想的话,你也可以理解为“无论字段的值如何,**字段的键都必须要是字符串的形式**,只不过,字段的键不可以是空字符串”。 ## 数组 ```json { "format_version": 2, "header": { "description": "resourcePack.vanilla.description", "name": "resourcePack.vanilla.name", "uuid": "0575c61f-a5da-4b7f-9961-ffda2908861e", "version": [0, 0, 1], "min_engine_version": [1, 13, 0] }, "modules": [ ] } ``` 除了上述我们已经多次观察的值的类型之外,JSON还允许一种特殊的数据类型,这种数据类型被称为**数组**(**Array**)。我们可以观察到,与对象非常类似的是,数组也使用一种形式的括号来作为两边的边界,只不过,数组使用的是方括号`[]`而非花括号。 我们之前已经知道,对象中的每一个字段都有其“名字”,即它的键,但是,数组中的值并没有与之对应的键,它们唯一的不同在于它们在数组中出现的顺序,即谁是第0位,谁是第1位,谁是第2位等。数组中只有值,数组中每一个值被称为一个**元素**(**Element**)。 和对象可以拥有任意多的字段一样,数组理论上也可以拥有任意多的元素,但是,有些位置的数组受到游戏接口的限制,只有一部分元素是有效的,且可以被游戏读取。比如,上述示例中的`"version"`和`"min_engine_version"`都只有前三个元素可以被游戏读取并正确解析为版本号,而`"modules"`字段则可以接受并正确读取任意多的元素。不过,这也仅仅是受限于游戏引擎提供的接口而已,这并不是本节想要讲述的内容。单纯从JSON格式上来看,不论你在数组中放置多少个元素,这个JSON文件都是符合格式标准的。 ```json { "format_version": 2, "header": { "description": "resourcePack.vanilla.description", "name": "resourcePack.vanilla.name", "uuid": "0575c61f-a5da-4b7f-9961-ffda2908861e", "version": [0, 0, 1], "min_engine_version": [1, 13, 0] }, "modules": [ { "description": "resourcePack.vanilla.description", "type": "resources", "uuid": "53644fac-a276-42e5-843f-a3c6f169a9ab", "version": [0, 0, 1] } ] } ``` 数组中和对象中字段的值所接受的类型并没有什么差别,比如上述例子中的`"modules"`数组的元素就是一个对象。数组中元素的顺序,或者说“位置”,被称为该元素的**索引**(**Index**)。注意,**索引都是从0开始计数的**,例如上述的`"modules"`数组只有一个元素,这个元素是一个对象,它的索引是0。 如果你还记得的话,我们一开始说过,JSON是从JavaScript语言中析取出来的一种格式。在JavaScript中,数组也是一种特殊的对象,或许是因为这个原因,在JSON中,人们有时也会使用一个JSON数组来作为JSON的根“对象”,这并非是一种错误的写法,只不过并不那么常见。以下是一个最外层(即根“对象”)是一个数组的示例: ```json [ "en_US", "zh_CN", "zh_TW" ] ``` ## 布尔值 为了纪念伟大的数学家与逻辑学家**乔治·布尔**(George Boole),人们将一种用于表示纯粹的“真”或“假”的概念的数据类型称为**布尔值**(**Boolean Value**,**boolean**,**bool**),这种值的类型被实现到了很多的计算机语言中,JSON中也不例外。在JSON中,我们使用`true`表示“**真**”或者“是”的概念,`false`表示“**假**”或者“否”的概念,二者皆为小写,不可以使用大写的形式。像`true`、`false`这样的预先给定了“只能这么写”的值在JSON中也被称为**字面量**(**Literal**),由于是直接的字面量,所以它们**不需要像字符串那样使用引号将自身括住**。以下是一个使用了布尔值的JSON示例: ```json { "name": "小明", "is_chinese": true, "is_american": false, "is_british": false, "is_japanese": false } ``` ## 空值 和布尔值一样,JSON中还有第三个字面量`null`,被称为**空值**(**Null**),用于代表“空”或“未知”的概念。空值`null`和数字中的`0`、字符串中的空字符串`""`、空对象`{}`、空数组`[]`都不同,它仅仅代表“这里什么都没有”或者“什么都不知道”。比如,我们可以问小明手里有几个苹果,如果回答“0”,那么我们就可以知道小明手里有0个苹果(即没有苹果),但是如果回答“Null”,结果就变成了我们无法知道小明手里有多少苹果,甚至小明有可能身患残疾,根本无法“手持”苹果了,这一点我们也无法从“Null”这个结果中肯定或否定。在一般的JSON编写中,我们并不经常会用到空值`null`,这个值一般是用于防止程序出现意外错误而引入的。注意,如同两个布尔值一样,`null`中的每一个字母也需要小写: ```json { "name": "小明", "handed_apple_count": null } ```