属性



属性是 CUE 一种标记形式,用于在 Cuelang 上构建工具。

cue 工具有一些预制的属性,你可以根据不同的用处定义自己的属性。

概览

属性是被加在 field 和 struct 上一种标记形式。

它们不会在求值时被处理,只是作为注释。它们也不能在 CUE 中被访问,而且需要你写 Go 去使用它们。

尽管是简单的标记,但是属性给自定义的 Go 工具提供强大的可扩展性和可配置型。

它们原本是为了辅助不同表现形式的映射,比如 Go 和 Protobuf。

然而,你可以给它们指定任何含义或行为,因为它们只能在你的应用中使用。

所以在这个意义上来说,它们和 Go 结构体的 tag 非常像。

属性有一些语法:

  • 它们以 @ 开头,有一个标签以及括号
  • 在字段后面或者在 struct 中
  • 可以带有几个可选值,并用逗号分割不同的 key
  • value 都是字符串,可以是任何你想要的格式

format.cue

	// field attribute
foo: "bar" @attr()

// declaration attribute
foo: {
	@attr()
	bar: string
}

// they can have keys
any: _ @attr(foo,bar)

// keys have optional values
any: _ @attr(key1,key2=value,key3="foo;bar")

cue 命令行的属性

cue 命令行工具有几个预定义的属性,你可以执行 cue help injection 参考。

@tag() 用于在命令行注入数据

你可以使用这个能力来注入数据和控制被计算的值。

inject.cue

package main

env:  string | *"dev" @tag(env)
host: "\(env).domain.com"

cue export inject.cue

env:  "dev"
host: "dev.domain.com"

cue export inject.cue -t env=prod

env:  "prod"
host: "prod.domain.com"

使用 type 选项来设置解释,也可以用 short 来说明可用值。

cue eval -t val=3.14 inject-type.cue

val: number @tag(val,type=int)

cue eval -t prod inject-short.cue

env: string @tag(env,short=prod|staging)
@if() 用于当某个 tag 设置时引用一个文件

用这个特殊的 tag 在求值时引用整个文件

if-main.cue

package main

import "path"

env:  string
host: string

// urlPath is agnostic of environment
urlPath: "/path/to/asset"

// url is derived from host and urlPath
url: "https://" + path.Join([host, urlPath])

if-qa.cue

@if(qa)
package main

env:  "qa"
host: "qa.prod.com"

if-prod.cue

@if(prod)
package main

env:  "prod"
host: "prod.mod.com"

cue eval .

import "path"

env:     string
host:    string
urlPath: "/path/to/asset"
url:     "https://" + path.Join([host, urlPath])

cue eval -t qa .

env:     "qa"
host:    "qa.prod.com"
urlPath: "/path/to/asset"
url:     "https://qa.prod.com/path/to/asset"

cue eval -t prod .

env:     "prod"
host:    "prod.mod.com"
urlPath: "/path/to/asset"
url:     "https://prod.mod.com/path/to/asset"
@go() 连接不同的表现形式

CUE 在被 Go 代码 import 的时候添加 struct 的 tag。 目前这些会被传递 ([go,yaml,json,toml,xml,protobuf])

@embed() 已经被提出用于在 CUE 中嵌入其他文件

和 Go 的嵌入系统差不多。

Propagation

属性如果在归一化、结构化嵌入以及导入过程中传播有一些规则。

这允许你给一个定义增加属性,然后他们将会被添加到 value 中,你也可以添加到属性。

propagations-fields.cue

	// Attributes are collected
x: _ @foo(bar) @cow(moo)
x: _ @foo(baz)

// this can be problematic
n: int @protobuf(1,int64)
n: int @protobuf(2,int64)

// field attributes don't propegate
y: x

cue eval -A propagation-fields.cue

x: _   @foo(bar) @cow(moo) @foo(baz)
n: int @protobuf(1,int64) @protobuf(2,int64)
y: _

propagations-struct.cue

#X: {
	@model(db)
		uuid: string @key(primary)
} @app(backend) // does not propagate

x: #X & {
	@model(ui) // can build up

	uuid: string @key(secondary) // can conflict
}

y: {
	#X
	uuid: "abc-123"
}

cue eval -A propagation-struct.cue

#X: {
	@model(db)
	uuid: string @key(primary)
} @app(backend)
x: {
	@model(db)

	@model(ui) // can build up
	uuid: string @key(primary) @key(secondary)
}

由于下面的问题,字段属性不会传播

field-propagation-issue.cue

#A: {
	x: int @protobuf(1,int64)
	y: int @protobuf(2,int64)
}

a: #A
a: {
	x: 1
	y: x // propagation here
}

cue eval -A field-propagation-issue.cue

#A: {
	x: int @protobuf(1,int64)
	y: int @protobuf(2,int64)
}
a: {
	x: 1 @protobuf(1,int64)
	y: 1 @protobuf(2,int64)
}

// would result in a conflict for indexes
a: {
	y: 1 @protobuf(1,int64) @protobuf(2,int64)
}

使用属性

必须通过 Go 代码来使用属性。

cue 通过预定义属性来实现。

go-api/attributes 这一节来获取更多细节和代码片段。

我们绝不会将你的邮箱分享给任何人。
2022 Hofstadter, Inc