指標基礎#
x := 42
p := &x // 取址
*p = 100 // 透過指標修改值
fmt.Println(x) // 100
// new 函式
ptr := new(int) // 配置記憶體並回傳指標
*ptr = 42可定址性規則#
不是所有值都可以取址。以下值不可定址:
- 常數
- 字面量(除了複合字面量)
- 函式呼叫的回傳值
- 型別轉換的結果
- 算術運算結果
// 不可定址
// _ = &10 // 錯誤:常數不可定址
// _ = &"hello" // 錯誤:字串字面量不可定址
// _ = &getValue() // 錯誤:函式回傳值不可定址
// 可定址
var x int = 10
_ = &x // 正確:變數可定址
s := []int{1, 2, 3}
_ = &s[0] // 正確:切片元素可定址
// 注意:陣列字面量元素不可定址
// arr := [3]int{1, 2, 3}
// _ = &arr[0] // 正確:變數陣列的元素可定址
// _ = &([3]int{1, 2, 3}[0]) // 錯誤:字面量陣列的元素不可定址unsafe.Pointer#
unsafe.Pointer 是通用指標型別,可以在不同指標型別間轉換:
import "unsafe"
var x int64 = 1
// 取得 x 的位址並轉換為 unsafe.Pointer
ptr := unsafe.Pointer(&x)
// 轉換為 *int64 並存取
y := *(*int64)(ptr)
fmt.Println(y) // 1
// 指標運算
// 取得 x 後面一個位元組的位址
nextByte := unsafe.Pointer(uintptr(ptr) + 1)
unsafe.Pointer繞過了 Go 的型別安全機制,要謹慎使用。錯誤的使用可能導致記憶體損壞或未定義行為。
常見的 unsafe 操作模式
// 模式 1:不同指標型別轉換
var f float64 = 1.5
bits := *(*uint64)(unsafe.Pointer(&f))
// 模式 2:指標運算
type Header struct {
Length int
Data [10]byte
}
h := &Header{Length: 5}
dataPtr := unsafe.Pointer(uintptr(unsafe.Pointer(h)) +
unsafe.Offsetof(h.Data))
// 模式 3:與 C 程式碼互動(cgo)
// 把 Go 指標轉換為 C 可用的指標指標 vs 值#
// 回傳指標的函式
func NewPerson(name string) *Person {
return &Person{Name: name} // Go 會自動把變數分配到堆上
}
// 回傳值的函式
func CreatePoint(x, y int) Point {
return Point{x, y} // 小型結構體,複製成本低
}用指標:
- 需要修改接收者/參數
- 結構體較大(通常 > 64 位元組)
- 需要表示「無值」的狀態(nil)
用值:
- 小型、不可變的資料
- 基本型別(int、string 等)
- 不需要共用狀態