Golang型別宣告與值賦予完全指南

Golang(Go語言)因其簡潔的語法和強大的型別系統而聞名。與其他程式語言不同,Go提供了多種宣告變數和型別的方式,同時具有靜態型別檢查的安全性。本文將詳細介紹Go語言中各種型別的宣告方式及如何為這些型別賦值。

1. 基本型別的宣告與賦值

1.1 數值型別

Go語言提供了豐富的數值型別,包括整數和浮點數。

整數型別

1
2
3
4
5
6
7
8
9
10
11
12
13
// 有符號整數:int, int8, int16, int32, int64
var a int = 10
var b int8 = 127 // -128 到 127
var c int16 = 32767 // -32768 到 32767
var d int32 = 2147483647
var e int64 = 9223372036854775807

// 無符號整數:uint, uint8, uint16, uint32, uint64, uintptr
var f uint = 10
var g uint8 = 255 // 0 到 255
var h uint16 = 65535
var i uint32 = 4294967295
var j uint64 = 18446744073709551615

浮點數型別

1
2
3
4
5
6
// 浮點數:float32, float64
var k float32 = 3.14
var l float64 = 3.141592653589793

// 科學記號表示法
var m float64 = 1.23e5 // 123000

複數型別

1
2
3
// 複數:complex64, complex128
var n complex64 = 3.0 + 4.0i
var o complex128 = complex(3.0, 4.0) // 使用complex函數構造

1.2 布林型別

1
2
3
// 布林型別:bool
var p bool = true
var q bool = false

1.3 字串型別

1
2
3
4
5
6
7
// 字串型別:string
var r string = "Hello, 世界"

// 多行字串(使用反引號)
var s string = `這是一個
多行字串,可以包含特殊字元如
\n 和 \t 而不需要轉義`

1.4 型別推斷

Go語言支援型別推斷,可以省略變數宣告時的型別:

1
2
3
4
5
6
7
8
9
10
// 使用:=運算符(短變數宣告)
t := 10 // int
u := 3.14 // float64
v := "Hello" // string
w := true // bool

// 使用var而不指定型別
var x = 10
var y = 3.14
var z = "Hello"

1.5 零值(預設值)

當宣告變數但不賦值時,Go會為每種型別賦予零值:

1
2
3
4
var a int     // 0
var b float64 // 0.0
var c string // ""(空字串)
var d bool // false

2. 複合型別的宣告與賦值

2.1 陣列(Array)

陣列是固定長度的同類元素序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 宣告並初始化陣列
var a [3]int = [3]int{1, 2, 3}

// 簡短宣告
b := [3]int{1, 2, 3}

// 使用...自動推導長度
c := [...]int{1, 2, 3, 4, 5} // 等同於[5]int{1, 2, 3, 4, 5}

// 指定索引初始化
d := [5]int{0: 10, 2: 30, 4: 50} // [10, 0, 30, 0, 50]

// 多維陣列
e := [2][3]int{
{1, 2, 3},
{4, 5, 6},
}

2.2 切片(Slice)

切片是對陣列的引用,長度可變。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 從陣列創建切片
arr := [5]int{1, 2, 3, 4, 5}
slice1 := arr[1:4] // [2, 3, 4]

// 直接宣告切片
var slice2 []int

// 使用字面量初始化切片
slice3 := []int{1, 2, 3}

// 使用make函數創建切片
slice4 := make([]int, 5) // 長度為5,容量為5的切片
slice5 := make([]int, 3, 5) // 長度為3,容量為5的切片

// 向切片添加元素
slice2 = append(slice2, 1, 2, 3)

2.3 映射(Map)

映射是鍵值對的無序集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 宣告映射
var m1 map[string]int

// 初始化映射
m1 = make(map[string]int)
m1["one"] = 1
m1["two"] = 2

// 字面量初始化
m2 := map[string]int{
"one": 1,
"two": 2,
"three": 3,
}

// 檢查鍵是否存在
value, exists := m2["four"]
if exists {
fmt.Println("Value:", value)
} else {
fmt.Println("Key 'four' does not exist")
}

// 刪除鍵值對
delete(m2, "two")

2.4 結構體(Struct)

結構體是字段的集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 宣告結構體類型
type Person struct {
Name string
Age int
Address Address
}

type Address struct {
City string
Country string
}

// 初始化結構體
var p1 Person
p1.Name = "Alice"
p1.Age = 30
p1.Address.City = "台北"
p1.Address.Country = "台灣"

// 使用字面量初始化
p2 := Person{
Name: "Bob",
Age: 25,
Address: Address{
City: "高雄",
Country: "台灣",
},
}

// 匿名結構體
point := struct {
X, Y int
}{
X: 10,
Y: 20,
}

2.5 指標(Pointer)

指標儲存變數的記憶體地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 宣告指標
var ptr *int

// 取址操作
var x int = 10
ptr = &x

// 通過指標修改值
*ptr = 20 // 現在x的值為20

// 使用new函數創建指標
ptr2 := new(int)
*ptr2 = 30

// 結構體指標
type User struct {
ID int
Name string
}

u := User{1, "張三"}
uPtr := &u
uPtr.Name = "李四" // 等同於(*uPtr).Name = "李四"

3. 函數與介面型別

3.1 函數型別

函數也可以作為一種型別。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 宣告函數型別
type MathFunc func(int, int) int

// 創建符合該型別的函數
func add(a, b int) int {
return a + b
}

func multiply(a, b int) int {
return a * b
}

// 使用函數型別
var operation MathFunc
operation = add
result := operation(5, 3) // 8

operation = multiply
result = operation(5, 3) // 15

3.2 介面(Interface)

介面定義了一組方法集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 宣告介面
type Shape interface {
Area() float64
Perimeter() float64
}

// 實現介面的結構體
type Rectangle struct {
Width, Height float64
}

func (r Rectangle) Area() float64 {
return r.Width * r.Height
}

func (r Rectangle) Perimeter() float64 {
return 2 * (r.Width + r.Height)
}

// 另一個實現介面的結構體
type Circle struct {
Radius float64
}

func (c Circle) Area() float64 {
return math.Pi * c.Radius * c.Radius
}

func (c Circle) Perimeter() float64 {
return 2 * math.Pi * c.Radius
}

// 使用介面
var s Shape
s = Rectangle{Width: 5, Height: 3}
fmt.Println("Rectangle area:", s.Area())

s = Circle{Radius: 2}
fmt.Println("Circle area:", s.Area())

3.3 空介面

空介面interface{}可以儲存任何型別的值,在Go 1.18後也可以使用any作為interface{}的別名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 宣告空介面變數
var i interface{}
// 等同於 var i any (Go 1.18+)

// 可以賦予任何型別的值
i = 42
i = "hello"
i = struct{ Name string }{"Alice"}

// 使用型別斷言獲取實際型別
str, ok := i.(string)
if ok {
fmt.Println("Value is a string:", str)
}

4. 容器與控制結構

4.1 通道(Channel)

通道用於goroutine之間的通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 宣告通道
var ch1 chan int // 雙向通道
var ch2 chan<- int // 僅發送通道
var ch3 <-chan int // 僅接收通道

// 初始化通道
ch1 = make(chan int) // 無緩衝通道
ch4 := make(chan int, 5) // 有緩衝通道,容量為5

// 發送與接收
go func() {
ch1 <- 10 // 發送值到通道
}()

value := <-ch1 // 從通道接收值

// 關閉通道
close(ch1)

// 遍歷通道(直到通道關閉)
for v := range ch4 {
fmt.Println(v)
}

4.2 型別別名與型別定義

1
2
3
4
5
6
7
8
// 型別別名 (Go 1.9+)
type MyInt = int // MyInt是int的別名

// 型別定義(創建新型別)
type Age int // Age是基於int的新型別

var a MyInt = 10 // a的型別實際上是int
var b Age = 20 // b的型別是Age,而不是int

5. 泛型(Go 1.18+)

從Go 1.18開始,Go語言引入了泛型支援。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 泛型函數
func Min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}

// 使用泛型函數
intResult := Min[int](10, 20)
floatResult := Min[float64](3.14, 2.71)

// 泛型型別
type Stack[T any] struct {
items []T
}

func (s *Stack[T]) Push(item T) {
s.items = append(s.items, item)
}

func (s *Stack[T]) Pop() (T, bool) {
var zero T
if len(s.items) == 0 {
return zero, false
}

n := len(s.items) - 1
item := s.items[n]
s.items = s.items[:n]
return item, true
}

// 創建泛型型別的實例
intStack := Stack[int]{}
intStack.Push(10)
intStack.Push(20)

stringStack := Stack[string]{}
stringStack.Push("Hello")
stringStack.Push("World")

6. 實用技巧與最佳實踐

6.1 多變數宣告

1
2
3
4
5
6
7
8
9
10
11
12
13
// 同時宣告多個變數
var a, b, c int

// 批量宣告不同型別的變數
var (
name string
age int
isActive bool
)

// 多變數初始化
var x, y, z int = 1, 2, 3
i, j := 4, "hello"

6.2 忽略部分返回值

使用下劃線_忽略不需要的返回值。

1
2
3
4
5
// 忽略第二個返回值
result, _ := strconv.Atoi("123")

// 僅獲取錯誤
_, err := os.Open("file.txt")

6.3 型別轉換

1
2
3
4
5
6
7
8
9
10
11
// 基本型別轉換
var i int = 42
var f float64 = float64(i)
var s string = strconv.Itoa(i) // 需要導入strconv包

// 結構體轉換(必須有相同的字段集)
type Point struct{ X, Y float64 }
type Vector struct{ X, Y float64 }

p := Point{1.0, 2.0}
v := Vector(p)

總結

Go語言的型別系統既簡潔又強大,通過各種宣告和初始化方式,開發者可以輕鬆處理不同的數據結構和編程需求。本文涵蓋了Go中常見的型別宣告方式及賦值技巧,從基本型別到複合型別,再到更高級的函數型別、介面和泛型。

理解並掌握這些型別操作,是成為Go語言高效開發者的基礎。希望本文能夠幫助您更好地理解Go語言的型別系統,並在實際編程中靈活應用。


參考資料:

  1. Go官方文檔:https://golang.org/doc/effective_go.html
  2. The Go Programming Language, Alan A. A. Donovan & Brian W. Kernighan