從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]
  • 修改元素

切片底層是數組,可像操做數組同樣直接使用下標進行操做。

相關文章
相關標籤/搜索