从其它平台迁移而来


静态数组

一维数组

声明

Delphi

1
var 数组名 : array[索引范围] of 元素类型; //索引范围是子界类型,格式为:下限..上限

Go

1
var 数组名 [数组长度]元素类型

Delphi的索引范围可以是任意的子界类型,而且是包含上下限的闭区间。子界可以是任意的序数类型(整型、字符型、枚举元素等),例如:0..85..11'a'..'z'等。子界元素就是数组元素的下标。

Go的数组长度只能是整型,下标为0~数组长度-1

初始化

Delphi

1
2
var 数组名 : array[1..N] of 元素类型 = (元素1, 元素2, ……, 元素N);
//如果先声明后赋值的话,赋值时就需要遍历数组对每个元素分别赋值

Go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
var 数组名 [N]元素类型 = [N]元素类型{元素0, 元素1, ……, 元素N-1}
//由于初始化时元素个数已知,以上代码也可写为:
var 数组名 [N]元素类型 = [...]元素类型{元素0, 元素1, ……, 元素N-1}
//如果先声明后赋值的话,写法如下:
var 数组名 [N]元素类型
数组名 = [...]元素类型{元素0, 元素1, ……, 元素N-1}
//也可简写为:
数组名 := [...]元素类型{元素0, 元素1, ……, 元素N-1}
//只初始化部分元素
数组名 := [N]元素类型{索引i: 元素i, 索引j: 元素j}
数组名 := [...]元素类型{索引i: 元素i, 索引j: 元素j}  //不指定数据长度时,数组为包含初始化元素的最小的数组

元素操作

Delphi

1
2
3
4
//取值
v := a[i];
//赋值
a[i] := v;

Go

1
2
3
4
//取值
v = a[i];
//赋值
a[i] = v;

遍历数组

Delphi

1
2
3
4
5
6
var a : array[m..n] of Integer;
for i := m to n do
  ……
//XE之后(也可能更早)也支持以下语法
for v in a do
  ……

Go

1
2
3
4
5
var a [N]int
for i, v := range a {
  ……
}
//也可以用传统写法,不过一般不那么写

比较数组

如果两个数组类型相同(包括数组的长度,数组中元素的类型)的情况下,如果两个数组的所有元素都是相等的时候数组才是相等的。

Delphi需要手动遍历比较。Go可以直接用==<>来比较。

二维数组

声明

Delphi

1
2
3
var
  数组名 : array[第一维索引范围] of array[第二维索引范围] of 元素类型;
  数组名 : array[第一维索引范围, 第二维索引范围] of 元素类型; //两种等效,一般使用这一种

Go

1
var 数组名 [第一维长度][第二维长度]元素类型

事实上,Go只有一维数组,但是一维数组同时也是一种数据类型,通过组合也可以实现概念上的二维甚至多维数组。例如,上面的[第二维长度]元素类型就是该二维数组的数据类型,而该数据类型本身又是个一维数组。

初始化

Delphi

1
var a: array[0..1, 0..2] of Integer = ((1, 2, 3), (4, 5, 6));

Go

1
2
3
4
5
6
7
8
9
var a [2][3]byte = [2][3]int{{1, 2, 3}, {4, 5, 6}}
//可简写为
a := [2][3]int{{1, 2, 3}, {4, 5, 6}}
//全部元素初始化时,第一维长度可以不指定,但第二维长度必须指定
a := [...][3]int{{1, 2, 3}, {4, 5, 6}}
//只初始化部分元素
a := [2][3]int{0: {1, 2, 3}} //初始化第一维第0个元素的全部元素
a := [2][3]int{1: {2: 6}}    //初始化第一维第1个元素的第二维第2个元素
a := [...][3]int{1: {2: 6}}  //不指定第一维长度时,数组为包含初始化元素的最小的数组

元素操作

Delphi

1
2
3
4
//取值
v := a[i, k];
//赋值
a[i, k] := v;

Go

1
2
3
4
//取值
v = a[i][j];
//赋值
a[i][j] = v;

遍历数组

Delphi

1
2
3
4
5
6
7
var a : array[m..n, x..y] of Integer;
for i := m to n do
  for j := x to y do
    ……
//XE之后(也可能更早)也支持以下语法
for v in a do
  ……

Go

1
2
3
4
5
6
7
var a [M][N]int
for i, ai := range a {
  for j, v := range ai {
    ……
  }
}
//也可以用传统写法,不过一般不那么写。另外可能有更好的方法而我不清楚

动态数组

Delphi

1
2
3
4
5
6
7
//声明
var da: array of Integer;
//构造
SetLength(da, 10); //首次调用会初始化元素,之后调用只分配长度不再初始化。
//具体使用与静态数组几乎完全一样
//静态数组的数组名事实上即指向该数组首地址的指针
//动态数组的数组名事实上指向该数组首地址的指针的指针

Go

Go没有动态数组,但是有更为灵活的切片切片完成可以实现动态数组的功能,而且更灵活更丰富。

切片

声明

1
2
var s1 []元素类型   //一维切片
var s2 [][]元素类型 //二维切片

初始化

  • 使用make()函数构造
1
2
3
4
5
6
切片名 = make([]元素类型, 元素个数, 切片容量)
//len()函数返回切片的元素个数
//cap()函数返回切片的容量
//切片容量可以省略,省略后切片的容量=元素个数
//切片容量不能小于元素个数,否则会报运行时错误
//切片容量可以大于元素个数,意为一次性预先分配出至少可以容纳该数量元素的内存供使用,若不够时会自动扩容,一般按容量的2倍进行扩容
  • 从已有数组或切片生成
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
切片名 = 已有切片[开始位置:结束位置]
//该语句并没有发生内存分配,而只是将新的切片指向了已有的切片,两个切片共用一部分内存
//len()函数会返回切片元素个数
//开始位置、结束位置均为原切片的索引,且开始位置<=结束位置
//新的切片包含开始位置,不包含结束位置,但结束位置可以等于元素个数,用于取出末位元素
//取出的元素数量为:结束位置-开始位置
//省略开始位置,表示从连续区域开头到结束位置
//省略结束位置,表示从开始位置到整个连续区域末尾
//两者同时省略,与切片本身等效
//两者相等,等效于空切片,一般用于切片复位

切片操作

  • 添加元素
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var s1, s2 []int
//添加一个元素
s1 = append(s1, 1)
//添加多个元素
s2 = append(s2, 2, 4, 6)
//添加一个切片的元素,必须加...对切片进行解包
s1 = append(s1, s2...)       //注意:不能同时既添加元素又添加切片
//第一个参数也可以是其它切片
s3 := append(s2, 8)          //s2也发生了变化
//在切片首部添加元素
s1 = append([]int{3}, s1...) //必定发生内存重新分配
//在切片第i个位置添加元素
s1 = append(s1[:i], append([]int{5}, s1[i:]...)...)
  • 切片拷贝
1
2
3
4
copy(目标切片, 源切片)
//目标切片必须分配过空间,且与源切片类型一致。
//若两个切片大小不一致,则按较少元素的切片的个数进行复制
//返回值为实际发生复制的元素个数
  • 删除元素

Go没有删除切片元素的语法或接口,但可以利用切片的特性。

1
2
3
4
5
6
7
8
9
//删除开头N个元素
s = s[N:]                   //移动指针
s = append(s[:0], s[N:]...) //移动数据
s = s[:copy(s, s[N:])]
//删除中间N个元素
s = append(s[:i], s[i+N:]...)
s = s[:i+copy(s[i:], s[i+N:])]
//删除尾部N个元素
s = s[:len(s)-N]
  • 修改元素

切片底层是数组,可像操作数组一样直接使用下标进行操作。