Go語言之陣列快速入門篇

尹正杰發表於2024-07-24

目錄
  • 一.陣列的定義
    • 1.陣列的引入
    • 2.陣列的概述
    • 3.陣列案例
    • 4.陣列的記憶體分析
    • 5.四種陣列初始化的方式
  • 二.陣列的遍歷
    • 1.陣列遍歷的方式
    • 2.for迴圈遍歷
    • 2.for range遍歷
  • 三.陣列的注意事項
    • 1.陣列長度屬於型別的一部分
    • 2.陣列屬於值型別,預設進行值傳遞
    • 3.陣列實現引用傳遞
  • 四.多維陣列
    • 1.字串二維陣列案例
    • 2.二維陣列的記憶體分析
    • 3.二維陣列的三種陣列初始化的方式
  • 五.二維陣列的遍歷
    • 1.基於for迴圈遍歷
    • 2.for range遍歷
  • 六.練習題
    • 1.將10以內的奇數放在同一個陣列中並求和
    • 2.找出陣列中和為指定值的兩個元素的下標

一.陣列的定義

1.陣列的引入

package main

import "fmt"

func main() {
	// 實現的功能,將西遊記師徒四人的分數求和,平均數
	tangsanzang := 100
	sunwukong := 99
	zhubajie := 88
	shaheshang := 77

	// 求和
	sum := tangsanzang + sunwukong + zhubajie + shaheshang

	// 求平均數
	avg := sum / 4

	fmt.Printf("西遊記師徒四人的總分: %d, 平均成績: %d\n", sum, avg)


	// 上述程式碼有個缺點,分數變數個數定義太多,不利於專案維護。
}

2.陣列的概述

陣列(array)是同一種資料型別元素的集合,其有以下3個特點:
	- 1.長度固定;
	- 2.連續記憶體空間;
	- 3.同一型別集合;

在Go語言中,陣列從宣告時就確定,使用時可以修改陣列成員,但是陣列大小不可變化。 


定義陣列的語法:
	var 陣列變數名 [元素數量]T

溫馨提示:
	陣列的長度必須是常量,並且長度是陣列型別的一部分。一旦定義,長度不能變。
	

3.陣列案例

package main

import "fmt"

func main() {

	// 定義一個長度為4的陣列
	var xiyouji [4]int

	// 使用一個變數就可以進行儲存
	xiyouji[0] = 100
	xiyouji[1] = 99
	xiyouji[2] = 88
	xiyouji[3] = 77

	// 求和
	sum := 0
	for i := 0; i < len(xiyouji); i++ {
		sum += xiyouji[i]
	}

	// 求平均數
	avg := sum / len(xiyouji)

	fmt.Printf("成績的總和: %v, 成績的平均數: %v\n", sum, avg)
}

4.陣列的記憶體分析

package main

import "fmt"

func main() {
	// 宣告長度為5的陣列
	var array [5]uint16

	// 陣列賦值
	array[0] = 100
	array[1] = 200
	array[2] = 300

	// 獲取陣列的長度
	fmt.Printf("陣列長度為:%d,陣列的內容:%v\n", len(array), array)

	// 陣列中儲存的地址
	fmt.Printf("陣列的地址:%p\n", &array)

	// 第一個空間的地址
	fmt.Printf("陣列的第一個地址:%p\n", &array[0])

	// 第二個空間的地址
	fmt.Printf("陣列的第二個地址:%p\n", &array[1])

	// 第三個空間的地址
	fmt.Printf("陣列的第三個地址:%p\n", &array[2])

	// 第四個空間的地址
	fmt.Printf("陣列的第二個地址:%p\n", &array[3])

	// 第五個空間的地址
	fmt.Printf("陣列的第三個地址:%p\n", &array[4])

}

5.四種陣列初始化的方式

package main

import "fmt"

func main() {

	var (

		// 第一種: 帶陣列型別初始化列表
		array01 [7]string = [7]string{"北京", "上海", "深圳", "西安", "成都", "杭州", "烏蘭察布"}

		// 第二種: 不帶陣列型別初始化列表
		array02 = [4]bool{false, true, true}

		// 第三種: 自行推斷長度
		array03 = [...]uint8{11, 22, 33, 44, 55}

		// 第四種: 指定索引值
		array04 = [...]int{1: 100, 3: -200, 5: 300}
	)

	fmt.Printf("array01型別: %T,值: %v, 長度: %d\n", array01, array01, len(array01))
	fmt.Printf("array02型別: %T,值: %v, 長度: %d\n", array02, array02, len(array02))
	fmt.Printf("array03型別: %T,值: %v, 長度: %d\n", array03, array03, len(array03))
	fmt.Printf("array04型別: %T,值: %v, 長度: %d\n", array04, array04, len(array04))

}

二.陣列的遍歷

1.陣列遍歷的方式

陣列的遍歷方式有兩種,即普通for迴圈和鍵值迴圈。

鍵值迴圈(for range)是GO語言特有的一種迭代結構,在許多情況下都非常有用,for  range看了眼遍歷陣列,切片,字串,map即通道。

for range語法上類似於其他語言中的foreach語句,一般形式如下:
  for key,value := range 陣列識別符號 {
    ...
  }
  
溫馨提示:
	1.陣列識別符號就是你定義的陣列變數;
	2.每次遍歷得到的索引用key接收,每次遍歷得到的索引位置上的值用value接收;
	3.key,value的名稱是隨便起名,比如可以寫成類似: "k,v"等;
	4.key,value屬於區域性變數,每次變數都被修改了資料;
	5.key,value的值如何你想忽略的話,接受的時候使用"_"代替即可;

2.for迴圈遍歷

package main

import "fmt"

func main() {
	// 功能實現: 手動錄入3個學生的分數,然後列印出來。
	var scores [3]int

	// 將分數儲存在陣列中:
	for i := 0; i < len(scores); i++ {
		fmt.Printf("請錄入第[%d]個學生的成績: ", i+1)
		fmt.Scanln(&scores[i])
	}

	// 使用for迴圈展示分數
	for i := 0; i < len(scores); i++ {
		fmt.Printf("第[%d]個學生的成績為: %d\n", i+1, scores[i])
	} 
}

2.for range遍歷

package main

import "fmt"

func main() {
	// 功能實現: 手動錄入3個學生的分數,然後列印出來。
	var scores [3]int

	// 將分數儲存在陣列中:
	for i := 0; i < len(scores); i++ {
		fmt.Printf("請錄入第[%d]個學生的成績: ", i+1)
		fmt.Scanln(&scores[i])
	}
 
	// 使用for-range迴圈展示分數
	for index, value := range scores {
		fmt.Printf("第[%d]個學生的成績為: %d\n", index+1, value)
	}
}

三.陣列的注意事項

1.陣列長度屬於型別的一部分

package main

import "fmt"

func main() {

	var (
		// 陣列長度屬於型別的一部分
		array01 = [3]int{3, 5, 7}
		array02 = [5]int{11, 22, 33, 44, 55}
	)

	fmt.Printf("array01陣列的型別為: %T,資料為: %v\n", array01, array01)
	fmt.Printf("array02陣列的型別為: %T,資料為: %v\n", array02, array02)

}

2.陣列屬於值型別,預設進行值傳遞

package main

import "fmt"

func setName(name [3]string) {
	name[0] = "JasonYin"

	fmt.Printf("in setName ... name = %v\n", name)
}

func main() {

	/*
	陣列是值型別,賦值和傳參會複製整個陣列。因此改變副本的值,不會改變本身的值。

	溫馨提示:
		(1)陣列支援"=="、"!="運算子,因為記憶體總是被初始化過的;
		(2)"[n]*T"表示指標陣列,"*[n]T"表示陣列指標; 
	*/

	var names = [3]string{"尹正傑", "yinzhengjie", "jasonyin2020"}

	fmt.Printf("呼叫setName前: in main ... names = %v\n", names)

	
	// 呼叫setName函式時,傳遞的陣列屬於值傳遞,因此setName內的修改並不會影響到main函式的陣列
	setName(names)

	fmt.Printf("呼叫setName後: in main ... names = %v\n", names)
}

3.陣列實現引用傳遞

package main

import "fmt"

// 接受的形參型別變為指標型別
func setName(name *[3]string) {

	// 取出指標的地址儲存的陣列地址,基於陣列的記憶體地址修改資料
	(*name)[0] = "JasonYin"

	fmt.Printf("in setName ... name = %v,地址: %p\n", name, name)
}

func main() {

	var names = [3]string{"尹正傑", "yinzhengjie", "jasonyin2020"}

	fmt.Printf("呼叫setName前: in main ... names = %v,地址: %p\n", names, &names)

	// 傳入names陣列的地址
	setName(&names)

	fmt.Printf("呼叫setName後: in main ... names = %v,地址: %p\n", names, &names)
}

四.多維陣列

1.字串二維陣列案例

package main

import (
	"fmt"
)

func main() {

	// 定義二維陣列,如果有元素預設進行初始化賦值,則有預設值("零值")
	address := [5][2]string{
		{"陝西省", "西安市"},
		{"河北省", "石家莊市"},
		{"黑龍江省", "哈爾濱"},
		{"江蘇省", "南京市"},
	}

	fmt.Println(address)

	// 支援索引取值
	fmt.Println(address[2][1])
}

2.二維陣列的記憶體分析

package main

import "fmt"

func main() {
	// 定義二維陣列,有預設的初始值
	var array [2][3]uint16

	// 二維陣列賦值
	array[0][0] = 100
	array[0][1] = 200
	array[1][1] = 300

	fmt.Printf("array地址: %p\n", &array)
	fmt.Printf("array[0]地址: %p\n", &array[0])
	fmt.Printf("array[0][0]地址: %p\n", &array[0][0])

	fmt.Printf("array[1]地址: %p\n", &array[1])
	fmt.Printf("array[1][0]地址: %p\n", &array[1][0])
	fmt.Printf("array[1][2]地址: %p\n", &array[1][2])
}

3.二維陣列的三種陣列初始化的方式

package main

import "fmt"

func main() {

	var (

		// 第一種: 帶陣列型別初始化列表
		array01 [5][2]string = [5][2]string{
			{"陝西省", "西安市"},
			{"河北省", "石家莊市"},
			{"黑龍江省", "哈爾濱"},
			{"江蘇省", "南京市"},
		}

		// 第二種: 不帶陣列型別初始化列表
		array02 = [4][2]bool{
			{true, false},
			{true, true},
			{false, false},
		}

		// 第三種: 自行推斷長度,多維陣列只有第一層可以使用"..."來讓編譯器推導陣列長度。
		array03 = [...][3]uint8{
			{1, 4, 7},
			{2, 5, 8},
			{3, 6, 9},
			{11, 22, 33},
			{44, 55, 66},
			{77, 88, 99},
		}

		// 不支援多維陣列的內層使用"...",會編譯報錯: "invalid use of [...] array (outside a composite literal)"
		// array03 = [3][...]uint8{
		// 	{11, 22, 33},
		// 	{44, 55, 66},
		// 	{77, 88, 99},
		// }
	)

	fmt.Printf("array01型別: %T,值: %v, 長度: %d\n", array01, array01, len(array01))
	fmt.Printf("array02型別: %T,值: %v, 長度: %d\n", array02, array02, len(array02))
	fmt.Printf("array03型別: %T,值: %v, 長度: %d\n", array03, array03, len(array03))

}

五.二維陣列的遍歷

1.基於for迴圈遍歷

package main

import "fmt"

func main() {
	// 定義二維陣列
	var city = [...][3]string{
		{"西安", "安康", "渭南"},
		{"石家莊", "邯鄲", "保定"},
		{"鄭州", "洛陽", "南陽"},
	}

	// 透過for迴圈遍歷
	for i := 0; i < len(city); i++ {
		for j := 0; j < len(city[i]); j++ {
			fmt.Print(city[i][j], "\t")
		}
		fmt.Println()
	}

}

2.for range遍歷

package main

import "fmt"

func main() {
	// 定義二維陣列
	var province = [...][3]string{
		{"西安", "安康", "渭南"},
		{"石家莊", "邯鄲", "保定"},
		{"鄭州", "洛陽", "南陽"},
	}

	// 透過for-range迴圈遍歷
	for index, city := range province {
		for key, value := range city {
			fmt.Printf("province[%d][%v] = %v\t\t", index, key, value)
		}
		fmt.Println()
	}

}

六.練習題

1.將10以內的奇數放在同一個陣列中並求和

package main

import (
	"fmt"
)

func main() {
	// 題意: 將10以內的奇數放在同一個陣列中並求和
	numberList := [5]int{1, 3, 5, 7, 9}

	var sum int

	for _, v := range numberList {
		sum += v
	}

	fmt.Println(sum)
}

2.找出陣列中和為指定值的兩個元素的下標

package main

import (
	"fmt"
)

func main() {
	// 找出陣列中和為指定值的兩個元素的下標,從陣列[1,3,5,7,8]中找出和為8的兩個元素元素的下標。

	// 需求分析:
	// 		(1)一次取出每個元素;
	//		(2)計算一下: other = 8 - 當前值;
	//		(3)上一步計算出other的值後再和現有陣列的元素進行比較,若存在就列印出來

	numberList := [5]int{1, 3, 5, 7, 8}

	for k1, v1 := range numberList {
		other := 8 - v1
		// 假設當前的索引是k1,則那另一個數字比較時選擇索引位置加一即可。
		for k2 := k1 + 1; k2 < len(numberList); k2++ {
			if numberList[k2] == other {
				fmt.Println(k1, k2)
			}
		}

		// 採用下面的迴圈方式會重複取索引喲~
		// for k2, v2 := range numberList {
		// 	if other == v2 {
		// 		fmt.Println(k1, k2)
		// 	}
		// }
	}
}

相關文章