Go 語言指針賦值的具體使用
1. 基本概念
指針是什么?
指針是存儲另一個變量內(nèi)存地址的變量。在 Go 中,指針用 * 符號表示。
基本語法
var ptr *int // 聲明一個指向 int 的指針 ptr = &value // 將 value 的地址賦值給 ptr *ptr = 100 // 通過指針修改值
2. 指針聲明和初始化
2.1 聲明指針
// 方式1: 先聲明,后賦值 var ptr *int var value int = 42 ptr = &value // 方式2: 聲明時初始化 ptr := &value // 方式3: 使用 new 函數(shù) ptr := new(int) *ptr = 42
2.2 結(jié)構(gòu)體指針
type Post struct {
ID uint
Title string
View int
}
// 方式1: 先創(chuàng)建結(jié)構(gòu)體,再取地址
post := Post{ID: 1, Title: "文章1", View: 100}
postPtr := &post
// 方式2: 直接創(chuàng)建結(jié)構(gòu)體指針
postPtr := &Post{ID: 1, Title: "文章1", View: 100}
// 方式3: 使用 new 函數(shù)
postPtr := new(Post)
postPtr.ID = 1
postPtr.Title = "文章1"
postPtr.View = 100
2.3 等價性
person := &Person{Name: "John", Age: 20}
// 這兩種寫法完全等價:
(*person).Name = "Jane" // 顯式解引用
person.Name = "Jane" // 隱式解引用(語法糖)
// 你寫的代碼
person.Name = "Jane"
// 編譯器實(shí)際生成的代碼
(*person).Name = "Jane"
3. 指針賦值操作
3.1 基本賦值
var num int = 42 ptr1 := &num ptr2 := ptr1 // ptr2 現(xiàn)在指向與 ptr1 相同的內(nèi)存地址 // 修改其中一個指針指向的值,另一個也會改變 *ptr1 = 100 fmt.Println(*ptr2) // 輸出: 100
3.2 切片中的指針賦值
// 指針切片
posts := []*Post{
{ID: 1, Title: "文章1", View: 10},
{ID: 2, Title: "文章2", View: 20},
}
// 獲取切片中元素的指針
firstPostPtr := posts[0]
firstPostPtr.Title = "修改后的文章1" // 這會修改原始數(shù)據(jù)
3.3 函數(shù)參數(shù)中的指針
func modifyPost(post *Post) {
post.Title = "修改后的標(biāo)題" // 修改會影響原始數(shù)據(jù)
}
post := Post{ID: 1, Title: "原始標(biāo)題", View: 0}
modifyPost(&post) // 傳遞地址
fmt.Println(post.Title) // 輸出: "修改后的標(biāo)題"
4. 指針的特殊情況
4.1 指針的零值
var ptr *Post // ptr 的零值是 nil
fmt.Println(ptr) // 輸出: <nil>
// 安全的 nil 指針檢查
if ptr != nil {
fmt.Println(ptr.Title)
} else {
fmt.Println("指針是 nil")
}
4.2 返回指針
func createPost(id uint, title string, view int) *Post {
post := Post{ID: id, Title: title, View: view}
return &post // Go 編譯器會優(yōu)化,不會返回棧上變量的地址
}
postPtr := createPost(1, "新文章", 100)
4.3 多重指針
value := 42
ptr := &value
ptrToPtr := &ptr
fmt.Printf("value = %d\n", value) // 42
fmt.Printf("*ptr = %d\n", *ptr) // 42
fmt.Printf("**ptrToPtr = %d\n", **ptrToPtr) // 42
5. 指針數(shù)組和數(shù)組指針
5.1 指針數(shù)組
// 指針數(shù)組:數(shù)組中的每個元素都是指針
numbers := []int{1, 2, 3}
pointerArray := [3]*int{&numbers[0], &numbers[1], &numbers[2]}
// 修改指針指向的值
*pointerArray[0] = 100
fmt.Println(numbers[0]) // 輸出: 100
5.2 數(shù)組指針
// 數(shù)組指針:指向整個數(shù)組的指針
numbers := [3]int{1, 2, 3}
arrayPointer := &numbers
// 通過數(shù)組指針訪問元素
fmt.Println(arrayPointer[0]) // 輸出: 1
fmt.Println((*arrayPointer)[0]) // 等價寫法
6. 常見陷阱和注意事項(xiàng)
6.1 循環(huán)中的指針問題
// ? 錯誤的方式:所有指針都指向同一個變量
numbers := []int{1, 2, 3}
var pointers []*int
for _, num := range numbers {
pointers = append(pointers, &num) // 錯誤!所有指針都指向循環(huán)變量
}
// ? 正確的方式:為每個值創(chuàng)建獨(dú)立的指針
var correctPointers []*int
for i := range numbers {
correctPointers = append(correctPointers, &numbers[i])
}
6.2 nil 指針解引用
var ptr *Post
// fmt.Println(ptr.Title) // 這會導(dǎo)致 panic
// 安全的訪問方式
if ptr != nil {
fmt.Println(ptr.Title)
}
6.3 返回局部變量地址
// 概念上不推薦,但 Go 編譯器會優(yōu)化
func badPractice() *Post {
post := Post{ID: 1, Title: "局部變量", View: 100}
return &post // Go 編譯器會優(yōu)化,不會返回棧上變量的地址
}
7. 實(shí)際應(yīng)用場景
7.1 數(shù)據(jù)庫操作(如項(xiàng)目中的使用)
func GetPostById(id uint) (*Post, error) {
var post Post
err := DB.First(&post, "id = ?", id).Error
return &post, err // 返回指針,避免大型結(jié)構(gòu)體的復(fù)制
}
7.2 函數(shù)參數(shù)傳遞
// 當(dāng)需要修改原始數(shù)據(jù)時使用指針
func UpdatePostView(post *Post) {
post.View++
}
// 當(dāng)不需要修改原始數(shù)據(jù)時使用值
func GetPostExcerpt(post Post) string {
return post.Title[:10] + "..."
}
7.3 切片和映射中的指針
// 指針切片:共享數(shù)據(jù)
posts := []*Post{
{ID: 1, Title: "文章1", View: 10},
{ID: 2, Title: "文章2", View: 20},
}
// 修改會影響原始數(shù)據(jù)
posts[0].Title = "修改后的文章1"
// 值切片:獨(dú)立副本
postValues := []Post{
{ID: 1, Title: "文章1", View: 10},
{ID: 2, Title: "文章2", View: 20},
}
// 修改不會影響原始數(shù)據(jù)
postValues[0].Title = "修改后的文章1"
8. 性能考慮
8.1 何時使用指針
- 大型結(jié)構(gòu)體:避免復(fù)制開銷
- 需要修改原始數(shù)據(jù):函數(shù)內(nèi)部修改需要影響調(diào)用者
- 接口實(shí)現(xiàn):某些接口要求指針接收者
8.2 何時使用值
- 小型結(jié)構(gòu)體:復(fù)制開銷小
- 不需要修改原始數(shù)據(jù):函數(shù)式編程風(fēng)格
- 需要數(shù)據(jù)隔離:確保數(shù)據(jù)不被意外修改
9. 最佳實(shí)踐
- 一致性:在項(xiàng)目中保持一致的指針使用風(fēng)格
- 明確意圖:使用指針明確表示需要修改數(shù)據(jù)
- nil 檢查:始終檢查指針是否為 nil
- 避免過度使用:不要為了使用指針而使用指針
- 文檔化:在函數(shù)文檔中說明參數(shù)和返回值的指針語義
10. 總結(jié)
Go 語言中的指針賦值是一個強(qiáng)大的特性,但需要謹(jǐn)慎使用:
- 指針賦值:兩個指針指向同一塊內(nèi)存
- 值賦值:創(chuàng)建數(shù)據(jù)的獨(dú)立副本
- 選擇原則:根據(jù)數(shù)據(jù)大小、修改需求和性能要求選擇
- 安全第一:始終進(jìn)行 nil 指針檢查
- 保持一致性:在項(xiàng)目中遵循統(tǒng)一的指針使用規(guī)范
到此這篇關(guān)于Go 語言指針賦值的具體使用的文章就介紹到這了,更多相關(guān)Go 語言指針賦值內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言開發(fā)框架反射機(jī)制及常見函數(shù)示例詳解
這篇文章主要為大家介紹了Go語言開發(fā)框架反射機(jī)制及常見函數(shù)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
golang處理TIFF圖像的實(shí)現(xiàn)示例
本文介紹了在Go語言中處理TIFF圖像,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-03-03
詳解如何通過Go來操作Redis實(shí)現(xiàn)簡單的讀寫操作
作為最常用的分布式緩存中間件——Redis,了解運(yùn)作原理和如何使用是十分有必要的,今天來學(xué)習(xí)如何通過Go來操作Redis實(shí)現(xiàn)基本的讀寫操作,需要的朋友可以參考下2023-09-09
基于Go語言實(shí)現(xiàn)一個并發(fā)下載器
這篇文章主要為大家詳細(xì)介紹了如何利用GO語言實(shí)現(xiàn)一個并發(fā)的文件下載器,可以在不重新啟動整個下載的情況下處理錯誤,感興趣的小伙伴可以了解一下2023-10-10
Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作
這篇文章主要介紹了Golang自定義結(jié)構(gòu)體轉(zhuǎn)map的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
關(guān)于Go 空結(jié)構(gòu)體的 3 種使用場景
在今天這篇文章要給大家介紹得是Go 語言中幾種常見類型的寬度,并且基于開頭的問題 ”空結(jié)構(gòu)體“ 進(jìn)行了剖析,需要的朋友可以參考一下,希望對你有所幫助2021-10-10

