Gox语言中的数组类型及其常用操作 - GX7.1

作为脚本语言,Gox语言中的复合类型当然会设计得更加方便一些,也很容易理解。由于Gox默认使用Qlang脚本引擎,Qlang中关于数组或者叫做切片(也就是Go语言中的slice,以后我们约定这两个称呼在Gox语言中表达的是同样的意思)的举例是这样的:

一般的切片用法(引自这里

a = [1, 2, 3] // 创建一个 int slice,并初始化为 [1, 2, 3]
b = [1, 2.3, 5] // 创建一个 float slice
c = ["a", "b", "c"] // 创建一个 string slice
d = ["a", 1, 2.3] // 创建一个 var slice (等价于 Go 语言的 []interface{})
e = make([]int, len, cap) // 创建一个 int slice,并将长度设置为 len,容量设置为 cap
f = make([][]int, len, cap) // 创建一个 []int 的 slice,并将长度设置为 len,容量设置为 cap
g = []byte{1, 2, 3} // 创建一个 byte slice,并初始化为 [1, 2, 3]
h = []byte(nil) // 创建一个空 byte slice

 

和 Go 语言类似,slice 有如下内置的操作:

a = append(a, 4, 5, 6) // 含义与 Go 语言完全一致
n = len(a) // 取 a 的元素个数
m = cap(a) // 取 slice a 的容量
ncopy = copy(a, b) // 复制 b 的内容到 a,复制的长度 ncopy = min(len(a), len(b))
b1 = b[2] // 取 b 这个 slice 中 index=2 的元素
b[2] = 888 // 设置 b 这个 slice 中 index=2 的元素值为 888
b[1], b[2], b[3] = 777, 888, 999 // 设置 b 这个 slice 中 index=1, 2, 3 的三个元素值
b2 = b[1:4] // 取子slice

 

特别地,在 qlang 中可以这样赋值:

x, y, z = [1, 2, 3]

结果是 x = 1, y = 2, z = 3。

 

实际上,qlang 支持多返回值就是通过 slice 的多赋值完成:

对于那些返回了多个值的 Go 函数,在 qlang 会理解为返回 var slice,也就是 []interface{}。
举个例子:

f, err = os.Open(fname)

这个例子,在 Go 里面返回的是 (*os.File, error)。但是 qlang 中是 var slice。

 

数组中的元素类型可变

来看看例子。

a = [1, 2, 3, "abc", 12.3]

println(a)

println(a[2])

println(len(a))

运行结果

可以看出,Gox语言中,数组的各个元素可以是不同的数据类型,本例中就包含了整型、浮点数和字符串三种数据类型。

数组可以直接用方括号来定义及赋值,如果要定义一个空数组,直接用“[]”这样的方式定义即可。

数组的索引和其他语言类似,是用方括号来进行索引。获取数组长度是使用内置函数len。

 

数组的更多操作

再看看数组更多的操作。

a = [1, 2, 3, "abc", 12.3]

println("a:", a)

println("a[2]:", a[2])

println("length of a:", len(a))

a = []var {1, 2}

a = append(a, "abc")
a = append(a, ["xyz", 16]...)

pv("a")

a[0]++

a[1] = [3.2, 16]

// a[6] = "5th"  // will index out of range

a[4] = 1000

a[len(a) - 1] = "last"

pv("a")

pl("a[1][1] = %v", a[1][1])

b = [19, 19]

pl("a + b = %v", append(a, b...))

c = append(append([a], [b]...), b...)

pv("c")

d = a[3:5]

pv("d")

e = remove(a, 1, 3)

pv("e")

f = make([][]bool, 1)

f[0] = make([]bool, 2)
f[0][0] = false
f[0][1] = true

pv("f")

g = []float64{1.2, 3, 56}

pv("g")

for i, v = range c {
    pl("i: %v, v: %v", i, v)
}

for i = 0; i < len(c); i ++ {
    pl("i: %v, v: %v", i, c[i])
}

运行结果是:

a: [1 2 3 abc 12.3]
a[2]: 3
length of a: 5
a([]interface {}): [1 2 abc xyz 16]
a([]interface {}): [2 [3.2 16] abc xyz last]
a[1][1] = 16
a + b = [2 [3.2 16] abc xyz last 19 19]
c([]interface {}): [[2 [3.2 16] abc xyz last] [19 19] 19 19]
d([]interface {}): [xyz last]
e([]interface {}): [2 last]
f([][]bool): [[false true]]
g([]float64): [1.2 3 56]
i: 0, v: [2 last abc xyz last]
i: 1, v: [19 19]
i: 2, v: 19
i: 3, v: 19
i: 0, v: [2 last abc xyz last]
i: 1, v: [19 19]
i: 2, v: 19
i: 3, v: 19

需要说明的是:

  • 数组的定义除了可以用方括号直接定义,也可以是包含类型说明的方式,如例子中的数组变量g定义的是float64类型的数组;
  • a变量的第二次定义是[]var类型的,这是相当于Go语言中interface{}的类型,表示类似C/C++语言中void*的概念,表示可以容纳各种类型,也就是说其中的值可以是任意类型。而上面的数组g由于定义为float64类型的数组,因此如果要给g增加一个非float64类型的数值,将会出错。
  • 数组可以直接用索引的方式修改其中的数值,也可以直接用“++”等操作符直接修改其中的数据;
  • 数组可以用类似Go语言中的append内置函数往里面添加元素,语法也与Go语言一致,是a = append(a, ...)的形式;
  • 如果是多维数组,可以用类似“a[1][1]”这样的方式去访问;
  • 两个数组可以也可以直接用append函数,但增加的变量或值后面要加上“...”表示增加的是一个数组,这样相加后的效果就是将两个数组合并;
  • 数组可以作切片操作,用类似“d = a[3:5]”的方式;
  • 数组中的元素可以用内置函数remove来删除,例如:“e = remove(a, 1, 3)”表示将数组a中的序号为1开始到序号为3的元素全部删除,并将结果赋值到新的数组变量e中(注意原数组a不变);
  • 数组也可以用内置函数make来初始化,注意此时其中仍然没有数值,需要添加,但也可以加上实际容量和预测容量两个参数,与Go语言的make也一致,形如a = make([]string, 0, 3),表示创建一个字符串切片,预留容量是3,当前预分配空间为0,也即是数组中实际没有任何一个数值,但预留3个的空间,这样如果最后实际数值不超过3个,则不会引起内存重新分配的动作,如果超过,会自动重新分配空间;
  • 数组的遍历可以使用for循环,传统的三段式for循环和for……range……的形式都可以;