前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >What is YAML (四)

What is YAML (四)

作者头像
CC老师
发布2021-08-25 14:54:08
1.2K0
发布2021-08-25 14:54:08
举报

YAML常用于配置/描述文件。比JSON更强调数据序列化、可视化、可读性和层次性。

JSON的语法本身是YAML1.2版的子集。换句话讲,YAMLJSON的严格超集,它可以做JSON可以做的一切,甚至更多。

Python一样,YAML使用缩进来表示嵌套,我们可以使用空格作为缩进,但不能使用Tab,制表符缩进是被禁止的。并且换行符和缩进在YAML中具有某种含义。

不像JSON,后者使用方括号和大括号。但是,JSON格式在YAML中是有效的。YAML文件使用.yml.yaml作为扩展名。

YAML快速入门

让我们来看一个简单的JSON文件。

代码语言:javascript
复制
{
  "macOS": "maOS Big Sur",
  "Swift": 5,
  "Air-pods": false,
  "iOS": {
    "version": 14.7
  },
  "Devices": [
    "iPhone",
    "iPad"
  ]
}

再来看它的YAML版本:

代码语言:javascript
复制
--- 
macOS: "maOS Big Sur"
Swift: 5
Air-pods: False
iOS:
  version: 14.7
Devices:
  - iPhone
  - iPad

YAML文件以---开头,表示新YAML文档的开始。以...表示文档结束。意味着,在同一个YAML文件里,可以定义多个YAML文档。

接下来,就是构成YAML文件中最基础的数据类型map,也就是JSON中的hash,也叫dictionary。文件以一个map开始,包含五个键值对,分别存储五种不同的数据类型:

  • macOS,指向字符串maOS Big Sur。字符串可以用单引号或双引号,或者根本不引号表示;
  • Swift,指向整数5YAML将未引号的数字识别为整数或浮点数;
  • Air-pods,代表了布尔值false
  • iOS,指向字典类型,并在里面使用了浮点数;
  • 最后一个Devices表示的数据类型以-开头,表示数组中的每一项数据。

接下来,我们具体看一下YAML中的数据类型。

YAML中的数据类型

标量(scalars)类型

除了上面我们提到的整数类型、浮点数类型、字符串、布尔值。YMAL还支持以下标量类型:

布尔类型

代码语言:javascript
复制
---
# True, On and Yes for true
foo: True
light: On
cat: Yes
bar: False
TV: Off
dog: No

null

代码语言:javascript
复制
---
foo: ~
bar: null

数字类型

代码语言:javascript
复制
---
foo: 12345
bar: 0x12d4
plop: 023332
ep:  12.3015e+05
na: .NAN

字符串类型

YAML字符串,在大多数情况下不需要使用引号:

代码语言:javascript
复制
---
paragraph: records separated by commas
   good choice for data transport

如果想使用转义字符,请使用双引号:

代码语言:javascript
复制
---
Superscript two: "\u00B2"
# YAML不会转义带有单引号的字符串
Superscript two s: '\u00B2'
Superscript two str: \u00B2

JSON版本:

代码语言:javascript
复制
{
  "Superscript two": "²",
  "Superscript two s": "\\u00B2",
  "Superscript two str": "\\u00B2"
}

如果想使用多行字符串,有几种方式。区别是,如何对待行尾的空格\换行符。

多行字符串,>折叠换行,也就是每一行行尾的空格不会转换成换行,空白行才视为换行:

代码语言:javascript
复制
---
paragraph: >
    records separated by commas
    good choice for data transport
    

多行字符串,|-作用与-相同,但是不保留最后一行的换行符:

代码语言:javascript
复制
---
paragraph: |-
   Or we
   can auto
   convert line breaks
   to save space
line: line

多行字符串,>+作用与>相同,保留最后一行的换行符:

代码语言:javascript
复制
---
# `>`折叠换行,每一行行尾的空格不会转换成换行,空白行才视为换行
paragraph: >
    records separated by commas
    good choice for data transport
# `-`保留换行,每行开头的缩进(以首行为基准)会被去除,而与首行不同的缩进会保留,行尾空格转换成换行符
paragraph1: |
    records separated by commas
    good choice for data transport
# `|-`作用与`-`相同,但是不保留最后一行的换行符
paragraph2: |-
   Or we
   can auto
   convert line breaks
   to save space
# `>+`作用与`>`相同,保留最后一行的换行符   
paragraph3: >+
 records separated by commas
   good choice for data transport
line: I am line.

JSON版本:

代码语言:javascript
复制
{
  "paragraph": "records separated by commas good choice for data transport\n",
  "paragraph1": "records separated by commas\ngood choice for data transport\n",
  "paragraph2": "Or we\ncan auto\nconvert line breaks\nto save space",
  "paragraph3": "records separated by commas\n  good choice for data transport\n",
  "line": "I am line."
}

数组

上述讲到的在YAML文件中声明数组的方式,需要特殊字符-和缩进配合。如果不希望使用缩进,也可以将数组的元素声明在一行,使用JSON的方式。同时,数组中的值不必是相同类型:

代码语言:javascript
复制
---
items: [ 1, 2, 3, 4, 5 ]
names: [ "one", "two", 1, 5 ]

字典

字典中的key可以用下划线、破折号或空格分隔。和数组一样,YAML中的字典,如果不喜欢使用缩进,也可以使用JSON的定义方式:

代码语言:javascript
复制
---
foo: { thing1: huey, thing2: louie, thing3: dewey }

如果一个key很复杂,比如多行字符串,使用?后面跟着一个空格,表示复杂key

代码语言:javascript
复制
---
? |
  This is a key
  that has multiple lines
: and this is its value

JSON版本:

代码语言:javascript
复制
{
  "This is a key\nthat has multiple lines\n": "and this is its value"
}

引用与合并

锚点符号&声明一个数据的别名。引用符号*,可以用来引用一个锚点数据:

代码语言:javascript
复制
---
array:
  - null_value:
  - boolean: true
  - integer: 1
  - alias: &example aliases are like variables
  - alias_1: *example

当前array的最后一个数据alias_1,直接使用倒数第二个alias的数据,JSON版本:

代码语言:javascript
复制
{
  "array": [
    {
      "null_value": null
    },
    {
      "boolean": true
    },
    {
      "integer": 1
    },
    {
      "alias": "aliases are like variables"
    },
    {
      "alias_1": "aliases are like variables"
    }
  ]
}

可以看到,alias_1alias保存的是相同的value

<<用来合并其他锚点字典到当前的字典中:

代码语言:javascript
复制
---
base : &base
  name: Everyone has same name 
  
alias: &example aliases are like 

array: &array
    - *base
  
foo:
  <<: *base
  base: *array

JSON版本:

代码语言:javascript
复制
{
  "base": {
    "name": "Everyone has same name"
  },
  "alias": "aliases are like",
  "array": [
    {
      "name": "Everyone has same name"
    }
  ],
  "foo": {
    "name": "Everyone has same name",
    "base": [
      {
        "name": "Everyone has same name"
      }
    ]
  }
}

set

代码语言:javascript
复制
---
set:
  ? item1
  ? item2
  ? item3
or: {item1, item2, item3}

JSON版本:

代码语言:javascript
复制
{
  "set": {
    "item1": null,
    "item2": null,
    "item3": null
  },
  "or": {
    "item1": null,
    "item2": null,
    "item3": null
  }
}

类型转换

YAML允许使用!!,显式声明数据类型:

代码语言:javascript
复制
---
explicit_string: !!str 0.5

explicit_int: !!int '0.4'

JSON版本:

代码语言:javascript
复制
{
  "explicit_string": "0.5",
  "explicit_int": 0.4
}

YAML文件在iOS中的应用--APINotes

我们在使用一些头文件的时候,可能会对头文件中的一些API添加一些专属的描述信息。此时,会导致头文件看上去非常的混乱。或许你的头文件来修改起来很多,很复杂。那么,这个时候,应该怎么办?

提供一个<name>.apinotesYAML格式的文件,放在头文件所在的目录中。同时向Clang传递-fapi-notes-modules参数,那么编译器在编译时,会自动去解析该文件对指定API的描述信息。

代码语言:javascript
复制
# APINotes包含一个YAML字典
# 最上层的Name,代表framework的module的名称
Name: SomeKit
# Classes, Protocols, Tags, Typedefs, Globals, Enumerators, Functions
# YAML数组。当前头文件的API信息描述
# Tags对应structs,enums,unions
# Enumerators对应enum cases
# Classes和Protocols下的每个条目都可以包含Methods和Properties数组
Classes:
  # YAML字典。此条目描述Class A
  - Name: A
    # 该类在Swift中的桥接名称,空字符串表示没有桥接
    SwiftBridge: 'Swift.A'
    # YAML数组。此条目描述Class A指定的methods
    Methods:
    # YAML字典。描述的selector
      - Selector: "transform:integer:"
        # selector类型:Instance 或者 Class
        MethodKind:      Instance
        # 宏NS_SWIFT_NAME。重新命名该OC方法在Swift中的名称
        SwiftName: "transform(_:integer:)"
        # YAML数组。提示是否为可选类型
        # ``Nonnull`` or ``N`` (等于``_Nonnull``)
        # ``Optional`` or ``O`` (等于``_Nullable``)
        # ``Unspecified`` or ``U`` (等于``_Null_unspecified``)
        # ``Scalar`` or ``S`` (deprecated)
        Nullability:      [ N, S ]
        # 提示返回值是否为可选类型。同上
        # 暂时有bug。建议使用ResultType
        NullabilityOfRet: N
      - Selector: "implicitGetOnlyInstance"
        MethodKind:      Instance
        # 等同于宏NS_SWIFT_UNAVAILABLE。声明此方法,不能在Swift使用
        Availability:    nonswift
        # 提示信息
        AvailabilityMsg: "getter gone"
        # 等同于宏NS_REFINED_FOR_SWIFT。
        # 由 Swift 导入此方法时,会在此方法前加入双下划线__
        # 类似Swift私有方法,便于在Swift中再进行扩展
        SwiftPrivate: true
      - Selector: "implicitGetOnlyClass"
        MethodKind:      Class
        Availability:    none
        AvailabilityMsg: "getter gone"
    Properties:
      # 描述的属性名称
      - Name: intValue
        # 属性的类别:Instance 或者 Class
        PropertyKind:    Instance
        Availability: none
        # 如果为真,该属性将在Swift中作为存储属性,而不是作为计算属性
        SwiftImportAsAccessors: false
        AvailabilityMsg: "wouldn't work anyway"
      - Name: MKErrorCode
        # NSError Code枚举
        NSErrorDomain: MKErrorDomain
      - Name: AVMediaType
        # NS_STRING_ENUM & NS_EXTENSIBLE_STRING_ENUM。是否可扩展
        # 三个选项:struct(可扩展)、enum、none
        SwiftWrapper: none
     - Name: GKPhotoSize
        # NS_ENUM & NS_OPTIONS
        # "NSEnum" / "CFEnum"
        # "NSClosedEnum" / "CFClosedEnum"
        # "NSOptions" / "CFOptions"
        # "none"
        EnumKind: none
  - Name: C
    Methods:
      - Selector: "initWithA:"
        MethodKind: Instance
        # 相当于宏NS_DESIGNATED_INITIALIZER,标记该方法必须在init方法中实现
        DesignatedInit: true
  - Name: OverriddenTypes
    Methods:
      - Selector: "methodToMangle:second:"
        MethodKind: Instance
        # 返回值类型,以及Nullability
        ResultType: 'NSArray * _Nonnull'
        Parameters:
          - Position: 0
            # 参数类型
            Type: 'SOMEKIT_DOUBLE *'
          - Position: 1
            Type: 'float *'
    Properties:
      - Name: intPropertyToMangle
        PropertyKind: Instance
        Type: 'double *'
Functions:
  - Name: global_int_fun
    ResultType: 'char *'
    Parameters:
      - Position: 0
        Type: 'double *'
      - Position: 1
        Type: 'void (^)()'
        # 相当于宏NS_NOESCAPE
        NoEscape: true
Globals:
  - Name: global_int_ptr
    Type: 'double (*)(int, void (^)())'
# 当前API对于Swift兼容描述
SwiftVersions:
  # 支持的最高版本
  - Version: 5.0
    # 同上
    Classes:
      - Name: A
        Methods:
          - Selector: "transform:integer:"
            MethodKind:      Instance
            NullabilityOfRet: O
            Nullability:      [ O, S ]
        Properties:
          - Name: explicitNonnullInstance
            PropertyKind:    Instance
            Nullability:     O
          - Name: explicitNullableInstance
            PropertyKind:    Instance
            Nullability:     N
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HelloCoder全栈小集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档