表达式



数学运算符

CUE 包含数字的标准的数学表达式,也可以在 string 或 list 中使用乘法。

math-ops.cue

// stdlib functions
import "math"

// mathematical!
n1: 3 + 2
n2: 3 - 2
n3: 3 * 2
n4: 3 / 2

// Truncated division
q: quo(-5, 2)
r: rem(-5, 2)

// Euclidean division
d: div(-5, 2)
m: mod(-5, 2)

// imported functions
f: math.Floor(3.14)
l: math.Log(100.2)
t: math.Tan(1.0)

cue eval math-ops.cue

n1: 5
n2: 1
n3: 6
n4: 1.5
q:  -2
r:  -1
d:  -3
m:  1
f:  3
l:  4.60716818865076442405424
t:  1.557407724654902

在 CUE 的 math package 中还有其他的运算操作。

比较运算符

CUE 拥有比较运算符和语义,值合并时会处理相等性检查。

compare-ops.cue

		// number constraints
positive:  >0 // numbers
doubledig: >=10 & <100 & int

// lexical comparison
lowercase: >="a" & <="z"

notone: <1 | >1
notone: 1 // error, empty disjuntion

cue eval compare-ops.cue

positive:  >0
doubledig: uint & >=10 & <100
lowercase: >="a" & <="z"
notone:    <1 | >1

预设范围

CUE 针对数字拥有以下预设的范围:

int8      >=-128 & <=127
int16     >=-32_768 & <=32_767
int32     >=-2_147_483_648 & <=2_147_483_647
int64     >=-9_223_372_036_854_775_808 & <=9_223_372_036_854_775_807
int128    >=-170_141_183_460_469_231_731_687_303_715_884_105_728 &
              <=170_141_183_460_469_231_731_687_303_715_884_105_727

uint      >=0
uint8     >=0 & <=255
uint16    >=0 & <=65536
uint32    >=0 & <=4_294_967_296
uint64    >=0 & <=18_446_744_073_709_551_615
uint128   >=0 & <=340_282_366_920_938_463_463_374_607_431_768_211_455

rune      >=0 & <=0x10FFFF

正则表达式

CUE 支持正则表达式,通过 =~!~ 进行限制。

regexp.cue

a: "hello world" & =~"^hello [a-z]+$"
b: "hello" & !~"^[A-Z]+"

lowercase: =~"^[a-z]+$"

c: "hello" & lowercase
d: "Hello" & lowercase // error

cue eval regexp.cue

a:         "hello world"
b:         "hello"
lowercase: =~"^[a-z]+$"
c:         "hello"

它们基于 Go 的正则表达式 , CUE 也有一些额外的 regexp helpers

嵌入

CUE 使用 \(<expr>) 就可以 string 或 byte 中插入值。

interpolate.cue

container: {
	repo:    "docker.io/cuelang"
	image:   "cue"
	version: "v0.3.0"
	full:    "\(repo)/\(image):\(version)"
}

name: "Tony"
msg:  "Hello \(name)"
// conver string to bytes
b: '\(msg)'
// convert bytes to string
s: "\(b)"

cue eval interpolate.cue

container: {
	repo:    "docker.io/cuelang"
	image:   "cue"
	version: "v0.3.0"
	full:    "docker.io/cuelang/cue:v0.3.0"
}
name: "Tony"
msg:  "Hello Tony"
b:    'Hello Tony'
s:    "Hello Tony"

更多复杂的场景,你可以使用 text/template 包。

你也可以插入字段名称(下面章节会讲)。

List 推导

CUE 可以通过 list 推导动态生成 list,可以遍历 list 或 struct 的字段。

形式是 [ for key, val in <iterable> [condition] { production } ]

* key 是 lists 的索引, 在 struct 中是字段的名称

list-comp.cue

nums: [1, 2, 3, 4, 5, 6]
sqrd: [ for _, n in nums {n * n}]
even: [ for _, n in nums if mod(n, 2) == 0 {n}]

listOfStructs: [ for p, n in nums {
	pos: p
	val: n
}]

extractVals: [ for p, S in listOfStructs {S.val}]

cue eval list-comp.cue

nums: [1, 2, 3, 4, 5, 6]
sqrd: [1, 4, 9, 16, 25, 36]
even: [2, 4, 6]
listOfStructs: [{
	pos: 0
	val: 1
}, {
	pos: 1
	val: 2
}, {
	pos: 2
	val: 3
}, {
	pos: 3
	val: 4
}, {
	pos: 4
	val: 5
}, {
	pos: 5
	val: 6
}]
extractVals: [1, 2, 3, 4, 5, 6]

每次条件判断只能引入一个元素 (https://github.com/cue-lang/cue/discussions/713)

可以使用 list.FlattenN 解决这个问题

Field 推导

CUE 也可以通过推导生成字段

field-comp.cue

apps: ["nginx", "express", "postgres"]
#labels: [string]: string
stack: {
	for i, app in apps {
		"\(app)": {
			name:   app
			labels: #labels & {
				app:  "foo"
				tier: "\(i)"
			}
		}
	}
}

cue eval field-comp.cue

apps: ["nginx", "express", "postgres"]
#labels: {}
stack: {
	nginx: {
		name: "nginx"
		labels: {
			app:  "foo"
			tier: "0"
		}
	}
	express: {
		name: "express"
		labels: {
			app:  "foo"
			tier: "1"
		}
	}
	postgres: {
		name: "postgres"
		labels: {
			app:  "foo"
			tier: "2"
		}
	}
}

条件字段

条件字段,或受保护的字段(技术上意味着保护),是另一种形式的字段推导

相对于通常意义的 if,有一些注意事项:

  • 没有 else 条件,必须有两个相反的判断条件
  • 不会忽略任何判断条件,所有的条件都会被计算

guards.cue

app: {
	name: string
	tech: string
	mem:  int

	if tech == "react" {
		tier: "frontend"
	}
	if tech != "react" {
		tier: "backend"
	}

	if mem < 1Gi {
		footprint: "small"
	}
	if mem >= 1Gi && mem < 4Gi {
		footprint: "medium"
	}
	if mem >= 4Gi {
		footprint: "large"
	}
}

// This will result in an error because CUE evaluates all conditions
// without short-circuiting, meaning it will still try to access app.field
// if app.field != _|_ && app.field == true {
//   foo: true
// }

// Use nested guards to check multiple conditions
if app.field != _|_ {
	if app.field == true {
		foo: true
	}
}
我们绝不会将你的邮箱分享给任何人。
2024 Hofstadter, Inc