Skip to main content
版本: 0.4.3

模型定义

KCL 的核心场景是写配置和校验,因此 KCL 被设计之初的一个核心特性就是建模,对应到 KCL 的关键字 schemaschema 可以被用于定义结构和约束,比如字段的类型,默认值,字段的范围和各种其他约束等内容。此外,使用 KCL schema 定义的结构可以反过来用于验证实现、验证输入(JSON、YAML 等结构化数据)或生成代码(生成多语言结构体、OpenAPI 等)。

定义结构和约束

比如我们有如下定义的 KCL 文件 (main.k)。在其中,我们使用 schema 关键字定义了三个模型 AppServiceVolume。并且 App 模型具有四个属性 domainType, containerPort, volumesservices,其中

  • domainType 的类型为字符串字面值联合类型,与“枚举”类似,这表明 domainType 的值只能取 "Standard", "Customized""Global" 中的一个
  • containerPort 的类型为整数 int, 此外我们使用 check 关键字定义了其取值范围 1 ~ 65535
  • services 的类型为 Service 列表类型,Service,并且我们用 ? 标记了它是一个可选属性,这意味着我们可以不为其赋值。
  • volumes 的类型为 Volume 列表类型,并且我们用 ? 标记了它是一个可选属性,这意味着我们可以不为其赋值。
schema App:
domainType: "Standard" | "Customized" | "Global"
containerPort: int
services?: [Service] # `?` specifies a optional attribute
volumes?: [Volume] # `?` specifies a optional attribute

check:
1 <= containerPort <= 65535 # `containerPort` must be in range [1, 65535]

schema Service:
clusterIP: str
$type: str

check:
clusterIP == "None" if $type == "ClusterIP" # When `type` is "ClusterIP", `clusterIP` must be `"None"`

schema Volume:
container: str = "*" # The default value of `container` is "*"
mountPath: str

check:
mountPath not in ["/", "/boot", "/home", "dev", "/etc", "/root"] # `mountPath` must not be one of the list `["/", "/boot", "/home", "dev", "/etc", "/root"]`

app: App {
domainType = "Standard"
containerPort = 80
volumes = [
{
mountPath = "/tmp"
}
]
services = [
{
clusterIP = "None"
$type = "ClusterIP"
}
]
}

我们使用如下命令行可以获得 app 实例的 YAML 输出

$ kcl main.k
app:
domainType: Standard
containerPort: 80
volumes:
- container: '*'
mountPath: /tmp
services:
- clusterIP: None
type: ClusterIP

此外,我们还可以将 App 模型放入单独的 app_module.k 中,在需要时我们可以在 main.k 中使用 import 关键字进行模块化管理,比如下面的文件结构

.
├── app_module.k
└── main.k

其中 app_module.k 的内容为

schema App:
domainType: "Standard" | "Customized" | "Global"
containerPort: int
volumes: [Volume]
services: [Service]

check:
1 <= containerPort <= 65535

schema Service:
clusterIP: str
$type: str

check:
clusterIP == "None" if $type == "ClusterIP"

schema Volume:
container: str = "*" # The default value of `container` is "*"
mountPath: str

check:
mountPath not in ["/", "/boot", "/home", "dev", "/etc", "/root"]

main.k 的内容为

import .app_module  # A relative path import

app: app_module.App {
domainType = "Standard"
containerPort = 80
volumes = [
{
mountPath = "/tmp"
}
]
services = [
{
clusterIP = "None"
$type = "ClusterIP"
}
]
}

我们使用如下命令行仍然可以获得 app 实例的 YAML 输出

$ kcl main.k
app:
domainType: Standard
containerPort: 80
volumes:
- container: '*'
mountPath: /tmp
services:
- clusterIP: None
type: ClusterIP