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