xia的小窩

一起來coding和碼字吧

0%

Golang-指標

這裡主要分成四個部分。

了解指標

當我們把 int, string, bool 這類值傳給函式處理時,Go語言會在函式裡複製這些值,建立新的變數。

這個複製動作意味著你在呼叫函式時,若函式對參數做出更動,原始的值也不會受到影響,能減少程式碼的錯誤。

對於這種傳值方式,Go語言採用了一種簡單的記憶體管理系統 — 堆疊 (Stack)

每個參數都會在堆疊中獲得自己的記憶體。缺點是有越來越多的數值在函式裡傳遞的時候,這樣的複製動作就會消耗掉記憶體。

其實還有一種方法,就是建立 指標 ,指標跟值是兩回事,而指標的唯一用途就是取得值而已。

對一個值建立指標後,Go 語言就無法以堆疊來管理該值所用的記憶體。這是 堆疊 必須仰賴的簡單變數範圍邏輯 ( scope loop ),以便得知如何回收該值所使用的記憶體,以上規則不適用於指標。

Go 語言轉而會把值放在所謂的 堆積 ( heap ) 記憶體空間 : 堆積勇許一個值存在,直到程式沒有任何指標參照到它為止。

Go 語言會使用所謂的 垃圾回收機制 ( garbage collection ) 程序來回收這些記憶體。

CPU vs 指標

如果以指標取代值來傳遞給大量函式,對記憶體的好處不可言喻,可是對 CPU 的負擔就很難評估了~

取得指標

可以使用 var

1
var <變數> *<type>

以這種方式的初始值會是 nil

使用 new()

1
2
<變數> := new(<type>)
var <變數> = new(<type>)

要取得某個既有變數的指標,請利用&算符

1
<變數 1> :=  &<變數2>

我們取一個例子

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
package main

import (
"fmt"
"time"
)

func main() {
var count1 *int
count2 := new(int)

countTemp := 5
count3 := &countTemp

t := &time.Time{}

fmt.Printf("count1 : %#v \n", count1)
fmt.Printf("count2 : %#v \n", count2)
fmt.Printf("count3 : %#v \n", count3)
fmt.Printf("t : %#v \n", t)
}

// count1 : (*int)(nil)
// count2 : (*int)(0xc000012098)
// count3 : (*int)(0xc0000120b0)
// t : time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC)

從指標取得值

如果要真正取得指標的關聯值 ( 即指標指向的記憶體所儲存的內容 ),必須把 * 算符放在變數名稱前面,以便解除 ( derefence ) 指標的參照、真正的取得值

1
<值> = *<指標變數>

接下來我們來實作

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
package main

import (
"fmt"
"time"
)

func main() {
var count1 *int
count2 := new(int)

countTemp := 5
count3 := &countTemp

t := &time.Time{}

if count1 != nil {
fmt.Printf("count1 : %#v \n", *count1)
}
if count2 != nil {
fmt.Printf("count2 : %#v \n", *count2)
}
if count3 != nil {
fmt.Printf("count3 : %#v \n", *count3)
}
if t != nil {
fmt.Printf("t : %#v \n", t.String())
}
}

// count2 : 0
// count3 : 5
// t : "0001-01-01 00:00:00 +0000 UTC"

使用指標的函式設計

這邊就直接實作 * 的部分

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
package main

import (
"fmt"
)

func add1(count int) {
count = count + 5
fmt.Println("add1 value: ", count)
}

func add2(count *int) {
*count = *count + 5
fmt.Println("add2 point: ", *count)
}

func main() {
var count int
add1(count)
fmt.Println("add1 post : ", count)
add2(&count)
fmt.Println("add2 post : ", count)
}

// add1 value: 5
// add1 post : 0
// add2 point: 5
// add2 post : 5