从Delphi到Go——数组

静态数组

一维数组

声明

Delphi数组

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

Goapp

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

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

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

初始化

Delphicode

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

Go索引

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接口

//取值
v := a[i];
//赋值
a[i] := v;

Go内存

//取值
v = a[i];
//赋值
a[i] = v;

遍历数组

Delphiclass

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

Go遍历

var a [N]int
for i, v := range a {
  ……
}
//也能够用传统写法,不过通常不那么写

比较数组

若是两个数组类型相同(包括数组的长度,数组中元素的类型)的状况下,若是两个数组的全部元素都是相等的时候数组才是相等的。

Delphi须要手动遍历比较。Go能够直接用==<>来比较。

二维数组

声明

Delphi

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

Go

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

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

初始化

Delphi

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

Go

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

//取值
v := a[i, k];
//赋值
a[i, k] := v;

Go

//取值
v = a[i][j];
//赋值
a[i][j] = v;

遍历数组

Delphi

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

var a [M][N]int
for i, ai := range a {
  for j, v := range ai {
    ……
  }
}
//也能够用传统写法,不过通常不那么写。另外可能有更好的方法而我不清楚

动态数组

Delphi

//声明
var da: array of Integer;
//构造
SetLength(da, 10); //首次调用会初始化元素,以后调用只分配长度再也不初始化。
//具体使用与静态数组几乎彻底同样
//静态数组的数组名事实上即指向该数组首地址的指针
//动态数组的数组名事实上指向该数组首地址的指针的指针

Go

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

切片

声明

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

初始化

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

切片操做

  • 添加元素
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:]...)...)
  • 切片拷贝
copy(目标切片, 源切片)
//目标切片必须分配过空间,且与源切片类型一致。
//若两个切片大小不一致,则按较少元素的切片的个数进行复制
//返回值为实际发生复制的元素个数
  • 删除元素

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

//删除开头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]
  • 修改元素

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

相关文章
相关标签/搜索