检查 Values



CUE Value类型有一系列方法,让我们得以检查他们的内容,状态和位置。 我们前面看到了如何打印完整的值及其错误状态,下面这些函数提供了更详细的细节。

本节我们在例子中会使用下面这个 CUE 文件。

value.cue

a: {
	b: "b"
	c: "c"
	e: int
}

d: {
	e: 42
	f: 3.14
	g: _
}

l: [1, 2, "y", "z"]
b: 'abc123'

r: s: d.e

LookupPath, Path

Path 方法返回到某个值的路径, 返回的路径可以在 LookupPath 函数中使用来获取值。 这两个函数可以看作两个相反的过程。

path.go

package main

import (
	"fmt"
	"os"

	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
)

func main() {
	c := cuecontext.New()

	// read and compile value
	d, _ := os.ReadFile("value.cue")
	val := c.CompileBytes(d)

	paths := []string{
		"a",
		"d.f",
		"l",
	}

	for _, path := range paths {
		fmt.Printf("====  %s  ====\n", path)
		v := val.LookupPath(cue.ParsePath(path))
		p := v.Path()
		fmt.Printf("%q\n%# v\n", p, v)
	}
}

go run path.go

====  a  ====
"a"
b: "b"
c: "c"
e: int
====  d.f  ====
"d.f"
3.14
====  l  ====
"l"
[1, 2, "y", "z"]

文档: LookupPath, Path

ReferencePath 和 Dereference

ReferencePath

reference.go

package main

import (
	"fmt"
	"os"

	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
)

func main() {
	c := cuecontext.New()

	// read and compile value
	d, _ := os.ReadFile("value.cue")
	val := c.CompileBytes(d)

	paths := []string{
		"d.f",
		"r.s",
	}

	for _, path := range paths {
		fmt.Printf("====  %s  ====\n", path)
		v := val.LookupPath(cue.ParsePath(path))
		p := v.Path()
		_, r := v.ReferencePath()
		fmt.Printf("%q %q\n%# v\n", p, r, v)
	}
}

go run reference.go

====  d.f  ====
"d.f" ""
3.14
====  r.s  ====
"r.s" "d.e"
d.e

文档: ReferencePath, Dereference

Exists 和 IsConcrete

当你查找一个 Value 时,你怎么知道他是否存在呢?(注意 LookupPath 函数总是会返回一个 Value) 这就用到了 Exists 方法。

IsConcrete 方法可以表明一个原子字段有数据或是一个错误。 对于列表或结构体类型,如果他们存在则返回true。 当使用析取和默认值时…

exists.go

package main

import (
	"fmt"
	"os"

	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
)

func main() {
	c := cuecontext.New()

	// read and compile value
	d, _ := os.ReadFile("value.cue")
	val := c.CompileBytes(d)

	paths := []string{
		"a",
		"d.g",
		"x.y",
	}

	for _, path := range paths {
		fmt.Printf("====  %s  ====\n", path)
		v := val.LookupPath(cue.ParsePath(path))
		p := v.Path()
		x := v.Exists()
		c := v.IsConcrete()
		fmt.Printf("%q %v %v\n%# v\n", p, x, c, v)
	}
}

go run exists.go

====  a  ====
"a" true true
b: "b"
c: "c"
e: int
====  d.g  ====
"d.g" true false
_
====  x.y  ====
"" false true
_|_ // field "x" not found

使用 Validate 方法检查一整个 value 是否是具体的。

文档: Exists, IsConcrete

Kind and IncompleteKind

KindIncompleteKind 方法能返回一个值的类型。 IncompleteKind 更加细粒度,而且不管一个值是否完整,都可以返回类型。(这个方法名看起来有点反了)

kind.go

package main

import (
	"fmt"
	"os"

	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
)

func main() {
	c := cuecontext.New()

	// read and compile value
	d, _ := os.ReadFile("value.cue")
	val := c.CompileBytes(d)

	paths := []string{
		"a",
		"a.e",
		"d.g",
		"l",
		"b",
		"x.y",
	}

	for _, path := range paths {
		v := val.LookupPath(cue.ParsePath(path))
		k := v.Kind()
		i := v.IncompleteKind()
		fmt.Printf("%q %v %v %v\n", path, k, i, v)
	}
}

go run kind.go

"a" struct struct {
	b: "b"
	c: "c"
	e: int
}
"a.e" _|_ int int
"d.g" _|_ _ _
"l" list list [1, 2, "y", "z"]
"b" bytes bytes 'abc123'
"x.y" _|_ _|_ _|_ // field "x" not found

你可以在这俩函数的返回值上用 switch 语句。

文档: Kinds, Kind, IncompleteKind

类型转换

Value 类型有一些函数可以把抽象类型转换为 Go 底层类型。 你应该首先确认 Value 的类型,再尝试转换。

conversions.go

package main

import (
	"fmt"
	"os"

	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
)

func main() {
	c := cuecontext.New()

	// read and compile value
	d, _ := os.ReadFile("value.cue")
	val := c.CompileBytes(d)

	var (
		s string
		b []byte
		i int64
		f float64
	)

	// read into Go basic types
	s, _ = val.LookupPath(cue.ParsePath("a.b")).String()
	b, _ = val.LookupPath(cue.ParsePath("b")).Bytes()
	i, _ = val.LookupPath(cue.ParsePath("d.e")).Int64()
	f, _ = val.LookupPath(cue.ParsePath("d.f")).Float64()

	fmt.Println(s, b, i, f)

	// an error
	s, err := val.LookupPath(cue.ParsePath("a.e")).String()
	if err != nil {
		fmt.Println(err)
	}

}

go run conversions.go

b [97 98 99 49 50 51] 42 3.14
a.e: cannot use value int (type int) as string

Len

Len 返回一个list的长度以及一个 bytes 里的字节数。

length.go

package main

import (
	"fmt"
	"os"

	"cuelang.org/go/cue"
	"cuelang.org/go/cue/cuecontext"
)

func main() {
	c := cuecontext.New()

	// read and compile value
	d, _ := os.ReadFile("value.cue")
	val := c.CompileBytes(d)

	paths := []string{
		"a",
		"d.e",
		"d.g",
		"l",
		"b",
	}

	for _, path := range paths {
		fmt.Printf("====  %s  ====\n", path)
		v := val.LookupPath(cue.ParsePath(path))
		p := v.Path()
		k := v.IncompleteKind()
		l := v.Len()
		fmt.Printf("%q %v %v\n%# v\n", p, k, l, v)
	}
}

go run length.go

====  a  ====
"a" struct _|_ // len not supported for type struct
b: "b"
c: "c"
e: int
====  d.g  ====
"d.g" _ _|_ // len not supported for type _|_
_
====  l  ====
"l" list 4
[1, 2, "y", "z"]
====  b  ====
"b" bytes 6
'abc123'

文档: Len

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