深入理解Golang中指針的用途與技巧
在 Go 語言中,指針是一種重要的概念。了解和正確使用指針對于理解語言的底層機制、編寫高效的代碼以及處理復雜數(shù)據(jù)結(jié)構(gòu)都非常關(guān)鍵。本文將深入探討 Golang 中指針的概念、用法。
1. 指針的基本概念和語法
指針是一個存儲變量內(nèi)存地址的變量。它提供了直接訪問內(nèi)存中數(shù)據(jù)的能力,可以用于改變變量的值。在Go語言中,使用 * 表示指針類型,通過 & 操作符獲取變量的地址,通過 * 操作符解引用指針獲取指針指向的值。
在 Go 語言中,每個變量在運行時都具有一個地址,該地址表示變量在內(nèi)存中的位置。要對變量進行"取地址"操作,可以在變量前加上 & 字符。此外,Go 語言中的值類型(如 int、float、bool、string、array 和 struct)都有相應的指針類型,分別為 *int、*float64、*bool、*string 等。
1.1 指針的聲明和初始化
在 Go 語言中,可以使用指針來引用任何類型的變量。指針的聲明和初始化可以通過如下語法完成:
var p *int // 聲明一個指向 int 類型的指針 p var str *string // 聲明一個指向 string 類型的指針 str
初始化指針可以通過 new 函數(shù)來分配內(nèi)存并返回指針的地址:
p := new(int) // 分配一個 int 類型的內(nèi)存,并將指針 p 指向該內(nèi)存
示例代碼:
package main
?
import "fmt"
?
func main() {
var p *int
var str *string
?
fmt.Printf("p: %v, str: %v\n", p, str) // 輸出 p: <nil>, str: <nil>
?
x := 10
p = &x // 將指針p指向變量x的地址
?
fmt.Printf("p: %v\n", p) // 輸出 p: 0xc0000100e0
fmt.Printf("*p: %d\n", *p) // 輸出 *p: 10
?
str = new(string) // 分配一個string類型的內(nèi)存,并將指針str指向該內(nèi)存
?
fmt.Printf("str: %v\n", str) // 輸出 str: 0xc000010120
fmt.Printf("*str: %s\n", *str) // 輸出 *str: ""
?
*str = "Hello, Go!" // 通過指針修改字符串的值
?
fmt.Printf("*str: %s\n", *str) // 輸出 *str: Hello, Go!
}1.2 獲取指針的地址和解引用
通過 & 操作符可以獲取變量的地址,例如:
x := 10 p := &x // 將指針 p 指向變量 x 的地址 ? a := 10 b := &a // 將指針 b 指向變量 a 的地址
我們來看一下 b := &a 的圖示:

使用 * 操作符可以解引用指針,獲取指針指向的值:
fmt.Println(*p) // 輸出指針 p 指向的值,即變量 x 的值
示例代碼:
func main() {
//指針取值
a := 10
b := &a // 取變量a的地址,將指針保存到b中
fmt.Printf("type of b:%T\n", b)
c := *b // 指針取值(根據(jù)指針去內(nèi)存取值)
fmt.Printf("type of c:%T\n", c)
fmt.Printf("value of c:%v\n", c)
}輸出如下:
type of b:*int
type of c:int
value of c:10
取地址操作符 & 和取值操作符 * 是一對互補操作符,& 取出地址,* 根據(jù)地址取出地址指向的值。
1.3 指針作為函數(shù)參數(shù)
在 Go 語言中,函數(shù)的參數(shù)傳遞默認是值傳遞。如果想要在函數(shù)內(nèi)部修改外部變量的值,可以通過傳遞指針來實現(xiàn)。
示例代碼:
package main
?
import "fmt"
?
func changeValue(ptr *int) {
*ptr = 20 // 修改指針指向的值
}
?
func main() {
x := 10
changeValue(&x) // 傳遞x的地址給changeValue函數(shù)
fmt.Println(x) // 輸出修改后的x的值,即20
}2. 指針的應用場景
指針在 Go 語言中有著廣泛的應用場景,下面將從幾個方面介紹指針的常見應用。
2.1 傳遞大對象
在函數(shù)參數(shù)傳遞時,如果直接傳遞大對象的副本,會產(chǎn)生額外的內(nèi)存開銷。通過傳遞指針,可以避免復制整個對象,提高程序的性能。
示例代碼:
package main
?
import "fmt"
?
type BigObject struct {
// 大對象的定義...
}
?
func processObject(obj *BigObject) {
// 對大對象進行處理...
}
?
func main() {
obj := BigObject{}
processObject(&obj) // 傳遞大對象的指針
}2.2 修改函數(shù)外部變量
通過指針,函數(shù)可以修改函數(shù)外部的變量。這在需要修改外部變量的值時非常有用,特別是在處理復雜數(shù)據(jù)結(jié)構(gòu)或需要對全局狀態(tài)進行修改的情況下。
示例代碼:
package main
?
import "fmt"
?
func modifyValue(ptr *int) {
*ptr = 30 // 修改指針指向的值
}
?
func main() {
x := 10
modifyValue(&x) // 傳遞x的地址給modifyValue函數(shù)
fmt.Println(x) // 輸出修改后的x的值,即30
}2.3 動態(tài)分配內(nèi)存
指針的另一個重要應用是動態(tài)分配內(nèi)存。通過 new 函數(shù)可以在堆上動態(tài)分配內(nèi)存,避免了在棧上分配固定大小的內(nèi)存空間的限制。這對于需要返回動態(tài)分配的數(shù)據(jù)或創(chuàng)建復雜數(shù)據(jù)結(jié)構(gòu)非常有用。
示例代碼:
package main
?
import "fmt"
?
type ComplexStruct struct {
// 復雜數(shù)據(jù)結(jié)構(gòu)的定義...
}
?
func createComplexStruct() *ComplexStruct {
cs := new(ComplexStruct) // 動態(tài)分配內(nèi)存并返回指針
// 初始化復雜數(shù)據(jù)結(jié)構(gòu)...
return cs
}
?
func main() {
obj := createComplexStruct()
// 對動態(tài)分配的數(shù)據(jù)結(jié)構(gòu)進行操作...
}2.4 函數(shù)返回指針
在函數(shù)中返回指針可以將函數(shù)內(nèi)部創(chuàng)建的變量的地址傳遞給調(diào)用者。這樣做可以避免復制整個變量,并允許調(diào)用者直接訪問和修改函數(shù)內(nèi)部的數(shù)據(jù)。
示例代碼:
package main
?
import "fmt"
?
func createValue() *int {
x := 10 // 在函數(shù)內(nèi)部創(chuàng)建變量
return &x // 返回變量的地址
}
?
func main() {
p := createValue()
fmt.Println(*p) // 輸出通過指針訪問的函數(shù)內(nèi)部變量的值,即10
}3. new 和 make
我們先來看一個例子:
func main() {
var a *int
*a = 100
fmt.Println(*a)
?
var b map[string]int
b["沙河娜扎"] = 100
fmt.Println(b)
}執(zhí)行上面的代碼會引發(fā) panic,為什么呢?在 Go 語言中,對于引用類型的變量,在使用之前需要先進行聲明,并為其分配內(nèi)存空間,否則無法存儲值。而對于值類型的聲明,無需手動分配內(nèi)存空間,因為它們在聲明時已經(jīng)默認分配了內(nèi)存空間。為了分配內(nèi)存空間,我們可以使用 Go 語言中內(nèi)建的兩個函數(shù):new 和 make。這兩個函數(shù)具有不同的用途,new 主要用于分配值類型的內(nèi)存空間,而 make 主要用于分配引用類型(如 slice、map 和 channel)的內(nèi)存空間。
3.1 new
new 是一個內(nèi)置的函數(shù),它的函數(shù)簽名如下:
func new(Type) *Type
Type 表示類型,new 函數(shù)只接受一個參數(shù),這個參數(shù)是一個類型,*Type 表示類型指針,new 函數(shù)返回一個指向該類型內(nèi)存地址的指針。
示例代碼:
func main() {
a := new(int)
b := new(bool)
fmt.Printf("%T\n", a) // *int
fmt.Printf("%T\n", b) // *bool
fmt.Println(*a) // 0
fmt.Println(*b) // false
}3.2 make
make 也是用于內(nèi)存分配的,區(qū)別于 new,它只用于 slice、map 以及 channel 的內(nèi)存創(chuàng)建,而且它返回的類型就是這三個類型本身,而不是他們的指針類型,因為這三種類型就是引用類型,所以就沒有必要返回他們的指針了。make 函數(shù)的函數(shù)簽名如下:
func make(t Type, size ...IntegerType) Type
make 函數(shù)是無可替代的,我們在使用 slice、map 以及 channel 的時候,都需要使用 make 進行初始化,然后才可以對它們進行操作。
示例代碼:
func main() {
var b map[string]int
b = make(map[string]int, 10)
b["沙河娜扎"] = 100
fmt.Println(b)
}4. 總結(jié)
指針是 Go 語言中一種重要的概念,它提供了直接訪問內(nèi)存和修改變量值的能力。正確使用指針可以提高程序的性能、處理復雜數(shù)據(jù)結(jié)構(gòu)以及實現(xiàn)并發(fā)編程中的數(shù)據(jù)共享和同步。
在編寫代碼時,我們應該充分理解指針的特性和使用注意事項,避免指針引起的錯誤和不確定性。合理使用指針將幫助我們編寫出高效、可靠且易于維護的 Go 語言程序。
到此這篇關(guān)于深入理解Golang中指針的用途與技巧的文章就介紹到這了,更多相關(guān)Golang指針內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang struct 實現(xiàn) interface的方法
這篇文章主要介紹了golang struct 實現(xiàn) interface的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07
Go?內(nèi)聯(lián)優(yōu)化讓程序員愛不釋手
這篇文章主要介紹了Go?內(nèi)聯(lián)優(yōu)化讓程序員愛不釋手,內(nèi)聯(lián)是在編譯過程中自動進行的一類基本優(yōu)化之一,文章圍繞主題展開更多詳細介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-06-06
這些關(guān)于Go中interface{}的注意事項你都了解嗎
這篇文章主要為大家詳細介紹了學習Go語言時需要了解的interface{}注意事項,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下2023-03-03
Golang實現(xiàn)對map的并發(fā)讀寫的方法示例
這篇文章主要介紹了Golang實現(xiàn)對map的并發(fā)讀寫的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03

