类型和数值
接下来介绍 CUE 的基本数据结构。
内置类型
CUE 有以下内置的类型,它们有意和 JSON 的类型对齐。
null bool string bytes number list struct
|
int
builtins.cue
N: null
B: bool
S: string
By: bytes
Num: number // Decimals or integers, a superclass if you will
Int: int // Big Int which can represent values without limits
List: [...]
Struct: {...}
Top 和 Bottom
Top 和 Bottom 是 CUE 的特殊类型,他们构成了 格 的两端。
“_
” 用来表示 top,可以匹配所有值,它也被称为 “any”。
“_|_
” 用来表示 bottom,代表错误。 (这个符号将来可能被一个关键词取代 )
Error
错误结果是在 bottom 并会携带错误信息,当从 CUE 导出数据而有未完成的类型,或在你代码包含冲突或无效的语义时,会发生错误。
errors.cue
s: "hello"
s: "world" // conflicting values "hello" and "world"
A: foo: "bar"
a: A.goo // undefined field A.goo (cue eval -c)
b: int // incomplete value (cue eval -c)
l: [ 1 , 2 ]
l: [ 1 , 3 ] // conflicting values 2 and 3
m: [ 1 , 2 ]
v: m[ 2 ] // index out of range
cue eval -c errors.cue
l.1: conflicting values 3 and 2:
./errors.cue:7:7
./errors.cue:8:7
s: conflicting values "world" and "hello":
./errors.cue:1:4
./errors.cue:2:4
注意,因为这个 issue 并不会展示所有的错误
空值结合运算
空值结合运算在发生错误时提供备选,这是个技术方面的错误合并,因为 null
是个有效值。
使用析取符和默认值可以设置。
coalesce.cue
elems: [ "a" , "b" , "c" ]
a: * elems[ 0 ] | "A"
// out of bounds error
d: * elems[ 3 ] | "D"
S: {
hello: "world"
}
// missing fields
s: * S.foo | "bar"
cue eval coalesce.cue
elems: [ "a" , "b" , "c" ]
a: "a"
d: "D"
S: {
hello: "world"
}
s: "bar"
Number
CUE 定义了两种数字类型:
int
是整数,通过 BigInt 实现以代表所有值,而且可以限制字节长度(像 int64)
number
是小数,(也不受字节长度限制, ?),整数也是 number
numbers.cue
a: int
a: 42
b: number
b: 3.14
c: int & 42.0 // conflict int and 42.0
d: 42 // will be type int
e: 3.14 // will be type number
CUE 也有一些数字的语法糖:
用 0x
, 0o
, 0b
分别代表十六进制(hex), 八进制(octal)和二进制(binary)
用 K, M, G, T, P
来表示数字大小,后面的 i
可以省略
e/E
表示十进制指数
可以用下划线让大数更具可读性
number-sugar.cue
hex: 0xdeadbeef
oct: 0o755
bin: 0b0101_0001
cpu: 0.5Mi
mem: 4Gi
mill: 1M
bill: 1G
zero: 0.0
half: 0.5
trim: 01.23
mole: 6.022_140_76e+23
tiny: 1.2345e-12
long: 23_456_789_000_000000
cue eval number-sugar.cue
hex: 3735928559
oct: 493
bin: 81
cpu: 524288
mem: 4294967296
mill: 1000000
bill: 1000000000
zero: 0
half: 0.5
trim: 1.23
mole: 6.02214076e+23
tiny: 1.2345e-12
long: 23456789000000000
String
CUE 的字符串是有效的 UTF-8 字符串,特殊字符可以转义表示。
strings.cue
str: "hello world"
smile: " \U0001F60A "
quoted: "you can \" quote by escaping \\ \" "
multiline: """
hello world
a "quoted string in a string"
down under
- some author
"""
cue eval strings.cue
str: "hello world"
smile: "😊"
quoted: "you can \" quote by escaping \\ \" "
multiline: """
hello world
a "quoted string in a string"
down under
- some author
"""
转义方式:
\a U+0007 alert or bell
\b U+0008 退格
\f U+000C 换页
\n U+000A 换行
\r U+000D 回车
\t U+0009 水平制表符
\v U+000b 垂直制表符
\/ U+002f 斜杠(solidus)
\\ U+005c 反斜杠
\' U+0027 单引号 (只在单引号引用的字符串中生效)
\" U+0022 双引号 (只在双引号引用的字符串中生效)
\nnn 八进制 (只在单引号引用的字符串中生效)
\xnn 十六进制 (只在单引号引用的字符串中生效)
\uXXXX for unicode
\UXXXXXXXX for longer unicode
https://cuelang.org/docs/references/spec/#string-and-byte-sequence-literals
在下面章节中还有一种字符串插值的转义。
“Raw” String
CUE 允许修改字符串分隔符,所以可以避免使用转义,通过在普通字符串两端添加任意数量的 #
就可以。
rawstrings.cue
str1: #"avoid using \ to "escape""#
str2: ## """
#"""
a nested multiline
string goes here
"""#
""" ##
cue eval rawstrings.cue --out json
{
"str1" : "avoid using \\ to \"escape\"" ,
"str2" : "#\"\"\"\na nested multiline\nstring goes here\n\"\"\"#"
}
Byte
字节是单引号引用并且输出时会被 base64 编码:
cue export bytes.cue --out json
List
CUE 的列表可以包含任意类型的元素,列表可以保持开放(Open)也可以预设一些元素,错误匹配的元素将会导致错误。
lists.cue
empty: []
any: [...]
ints: [... int ]
nested: [...[... string ]]
opened: ints & [ 1 , 2 , ...]
closed: ints & [ 1 , 2 , 3 ]
// list of for constrained ints
ip: 4 * [ uint8 ]
// sets the first element
tendot: ip & [ 10 , ... uint8 ]
// uses constraint as second element
one72: ip & [ 172 , >= 16 & <= 32 , ...]
mixed: any & [...] & [ "a" , 1 , {foo: "bar" }]
join: [ 1 , 2 ] + [ 3 , 4 ]
Join: opened & join
cue eval lists.cue
empty: []
any: []
ints: []
nested: []
opened: [ 1 , 2 ]
closed: [ 1 , 2 , 3 ]
ip: [ uint8 , uint8 , uint8 , uint8 ]
tendot: [ 10 , uint8 , uint8 , uint8 ]
one72: [ 172 , uint & >= 16 & <= 32 , uint8 , uint8 ]
mixed: [ "a" , 1 , {
foo: "bar"
}]
join: [ 1 , 2 , 3 , 4 ]
Join: [ 1 , 2 , 3 , 4 ]
Struct
struct 很像 JSON 对象,它们是 CUE 主要的复合类型。
struct 包含一组字段 (label: value)。
默认情况下,struct 是开放(Open)的,可以被添加更多字段。
structs.cue
// an open struct
a: {
foo: "bar"
}
// shorthand nested field
a: hello: "world"
// a closed struct
b: close ({
left: "right"
})
// error, field up not allowed
b: up: "down"
Definition
Definition
很像 struct,主要用于定义结构。
它们默认情况下是封闭(Close)的,而且 CUE 导出时 不会 被输出。
defns.cue
#schema: {
word: string
num: int | * 42
optional?: string
}
value: #schema & {
word: "what's the good?"
}
cue eval defns.cue
#schema: {
word: string
num: 42
}
value: {
word: "what's the good?"
num: 42
}
cue export defns.cue
{
"value" : {
"word" : "what's the good?"
"num" : 42
}
}
嵌套
可以在任意一个 struct 或 definition 中嵌套另一个 struct 或 definition 来构建数据。
通过开放的 struct / definition 和连接符实现同样的效果,但是通常不能修改嵌套的内容。
embed.cue
#A: {
num: number
}
#B: {
ans: string
}
// this won't work
#bad: #A & #B
bad: #bad & {
num: 42
ans: "life"
}
// but this will
#val: {#A, #B}
val: #val & {
num: 42
ans: "life"
}
cue export embed.cue
{
"val" : {
"num" : 42
"ans" : "life"
}
}
模式匹配约束
模式匹配现在允许对通过匹配的标签进行特定的约束。
目前来说还不成熟,但是当 query 提案 接受并实现之后,会变得更强大。
目前,你可以对字符串类型的标签约束,然后将其设为你想要设置的字段的值。
patterns.cue
#schema: {
name: string
ans: string
num: int | * 42
}
// match elem fields and alias labels to Name,
// unify with schema, set name to Name by label
elems: [Name= _ ]: #schema & {name: Name}
elems: {
one: {
ans: "solo"
num: 1
}
two: {
ans: "life"
}
}
elems: other: {ans: "id" , num: 23 }
cue export patterns.cue
{
"elems" : {
"one" : {
"name" : "one"
"ans" : "solo"
"num" : 1
}
"other" : {
"name" : "other"
"ans" : "id"
"num" : 23
}
"two" : {
"name" : "two"
"ans" : "life"
"num" : 42
}
}
}