开放性和封闭性



封闭性从扩展性的角度描述值的状态,简单来说,封闭的值不能添加字段,但是开放的值可以。

有很多规则来决定一个值是不是封闭状态,也有很多结构可以定义字段。

所以刚开始也不必担心有点不好理解,因为实现会更复杂!


struct 默认是开放的

struct 默认是开放和可以扩展的,你可以直接新增字段或者在连接符后新增字段。

并且对于 struct 所有的字段也都是开放和可扩展的。

struct.cue

S: {
	name: string
	point: {
		x: int
		y: int
	}
}

// we can extend the fields
s: S & {
	data: bytes
	point: z: int
}

定义(Definition) 默认是封闭的

定义默认会有个固定的结构,确定不会有额外的字段可以添加。

同样的对于它的所有字段也是一样的。

definition.cue

#D: {
	name: string
	data: {
		num: int
	}
}

// you can split the spec, this is not extension
#D: tags: [...string]

// after conjuncting, extension is not allowed
d: #D & {
	meta: string
	data: {
		val: string
	}
}

开放、封闭值

你可以使用 ... 开放定义(Definition),也可以使用 close 来封闭 struct。

但是不会递归的应用到所有的字段,只会针对使用关键字的字段生效。

open-n-close.cue

S: close({
	name: string
	point: {
		x: int
		y: int
	}
})

s: S & {
	// this is no longer allowed
	data: bytes
	// this is still allowed
	point: z: int
}

#D: {
	name: string
	data: {
		num: int
		...
	}
	...
}

// this is now allowed
d: #D & {
	meta: string
	data: {
		val: string
	}
}

正则模式约束的封闭性

正则的模式约束会定义一组值。所以即使 d & #D 是封闭的,但是仍然可以定义无限的 label。

pattern-constraints.cue

#D: {
	labels: [=~"dev"]: string
}

d: #D & {
	labels: {
		// allowed
		"devUser": "foo"
		// not allowed
		"appUser": "bar"
	}
}

通过嵌入扩展定义

嵌入允许扩展定义,当 #D 被修改时,被嵌入的新定义也能更新。

embed.cue

#D: {
	name: string
	data: {
		num: int
	}
}

// embed D into a new definition
#L: {
	#D
	tags: [...string]
}

// after conjuncting, extension is not allowed
d: #L & {
	meta: "meta"
	data: {
		num: 3
	}
	tags: ["foo", "bar"]
}

隐藏字段

你可以给一个封闭的值添加隐藏的字段,对于定义或者使用 close() 被封闭的 struct 都可以生效。

hidden.cue

#D: {
	size: string
	data: {
		x: int
		y: int
	}
}

// after conjuncting, extension is not allowed
d: #D & {
	data: {
		x: 3
		y: 4
	}

	_calc: data.x * data.y
	size:  string | *"med"
	if _calc < 10 {
		size: "small"
	}
	if _calc > 100 {
		size: "large"
	}
}

List 的封闭性

List 的开放和封闭性比 struct 和 定义 的要简单很多,如果使用了省略号(...),list 就是开放的。

任何固定的元素都需要在确定的位置上,类型必须对应。

list.cue

// an open list
L1: [...]

// one element list with any type
L2: [_]

// an int list with at least one element
L3: [int, ...]

// a mixed list of four elements
L4: [int, string, {...}, _]

// you can concatenate lists too
L5: L2 + L3 // open
L6: L2 + L4 // closed
L7: L3 + L2 // closed, L3 ellipses removed

// You cannot append or reopen like this
L2: L2 + [...]
我们绝不会将你的邮箱分享给任何人。
2022 Hofstadter, Inc