新聞中心
與 Java 和 .NET 等編程語(yǔ)言不同,Go語(yǔ)言為程序員提供了控制 數(shù)據(jù)結(jié)構(gòu)指針的能力,但是,并不能進(jìn)行指針運(yùn)算。Go語(yǔ)言允許你控制特定集合的數(shù)據(jù)結(jié)構(gòu)、分配的數(shù)量以及內(nèi)存訪問(wèn)模式,這對(duì)于構(gòu)建運(yùn)行良好的系統(tǒng)是非常重要的。指針對(duì)于性能的影響不言而喻,如果你想要做系統(tǒng)編程、操作系統(tǒng)或者網(wǎng)絡(luò)應(yīng)用,指針更是不可或缺的一部分。

成都創(chuàng)新互聯(lián)公司專注于企業(yè)成都全網(wǎng)營(yíng)銷推廣、網(wǎng)站重做改版、山亭網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、html5、購(gòu)物商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為山亭等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。
指針(pointer)在Go語(yǔ)言中可以被拆分為兩個(gè)核心概念:
- 類型指針,允許對(duì)這個(gè)指針類型的數(shù)據(jù)進(jìn)行修改,傳遞數(shù)據(jù)可以直接使用指針,而無(wú)須拷貝數(shù)據(jù),類型指針不能進(jìn)行偏移和運(yùn)算。
- 切片,由指向起始元素的原始指針、元素?cái)?shù)量和容量組成。
受益于這樣的約束和拆分,Go語(yǔ)言的指針類型變量即擁有指針高效訪問(wèn)的特點(diǎn),又不會(huì)發(fā)生指針偏移,從而避免了非法修改關(guān)鍵性數(shù)據(jù)的問(wèn)題。同時(shí),垃圾回收也比較容易對(duì)不會(huì)發(fā)生偏移的指針進(jìn)行檢索和回收。
切片比原始指針具備更強(qiáng)大的特性,而且更為安全。切片在發(fā)生越界時(shí),運(yùn)行時(shí)會(huì)報(bào)出宕機(jī),并打出堆棧,而原始指針只會(huì)崩潰。
C/C++中的指針
說(shuō)到 C/C++ 中的指針,會(huì)讓許多人“談虎色變”,尤其是對(duì)指針的偏移、運(yùn)算和轉(zhuǎn)換。
其實(shí),指針是 C/C++ 語(yǔ)言擁有極高性能的根本所在,在操作大塊數(shù)據(jù)和做偏移時(shí)即方便又便捷。因此,操作系統(tǒng)依然使用C語(yǔ)言及指針的特性進(jìn)行編寫(xiě)。
C/C++ 中指針飽受詬病的根本原因是指針的運(yùn)算和內(nèi)存釋放,C/C++ 語(yǔ)言中的裸指針可以自由偏移,甚至可以在某些情況下偏移進(jìn)入操作系統(tǒng)的核心區(qū)域,我們的計(jì)算機(jī)操作系統(tǒng)經(jīng)常需要更新、修復(fù)漏洞的本質(zhì),就是為解決指針越界訪問(wèn)所導(dǎo)致的“緩沖區(qū)溢出”的問(wèn)題。
要明白指針,需要知道幾個(gè)概念:指針地址、指針類型和指針取值,下面將展開(kāi)詳細(xì)說(shuō)明。
認(rèn)識(shí)指針地址和指針類型
一個(gè)指針變量可以指向任何一個(gè)值的內(nèi)存地址,它所指向的值的內(nèi)存地址在 32 和 64 位機(jī)器上分別占用 4 或 8 個(gè)字節(jié),占用字節(jié)的大小與所指向的值的大小無(wú)關(guān)。當(dāng)一個(gè)指針被定義后沒(méi)有分配到任何變量時(shí),它的默認(rèn)值為 nil。指針變量通??s寫(xiě)為 ptr。
每個(gè)變量在運(yùn)行時(shí)都擁有一個(gè)地址,這個(gè)地址代表變量在內(nèi)存中的位置。Go語(yǔ)言中使用在變量名前面添加
&操作符(前綴)來(lái)獲取變量的內(nèi)存地址(取地址操作),格式如下:
ptr := &v // v 的類型為 T
其中 v 代表被取地址的變量,變量 v 的地址使用變量 ptr 進(jìn)行接收,ptr 的類型為
*T,稱做 T 的指針類型,
*代表指針。
指針實(shí)際用法,可以通過(guò)下面的例子了解:
package main
import (
"fmt"
)
func main() {
var cat int = 1
var str string = "banana"
fmt.Printf("%p %p", &cat, &str)
}運(yùn)行結(jié)果:
0xc042052088 0xc0420461b0
代碼說(shuō)明如下:
- 第 8 行,聲明整型變量 cat。
- 第 9 行,聲明字符串變量 str。
- 第 10 行,使用 fmt.Printf 的動(dòng)詞
%p打印 cat 和 str 變量的內(nèi)存地址,指針的值是帶有0x十六進(jìn)制前綴的一組數(shù)據(jù)。
提示:變量、指針和地址三者的關(guān)系是,每個(gè)變量都擁有地址,指針的值就是地址。
從指針獲取指針指向的值
當(dāng)使用
&操作符對(duì)普通變量進(jìn)行取地址操作并得到變量的指針后,可以對(duì)指針使用
*操作符,也就是指針取值,代碼如下。
package main
import (
"fmt"
)
func main() {
// 準(zhǔn)備一個(gè)字符串類型
var house = "Malibu Point 10880, 90265"
// 對(duì)字符串取地址, ptr類型為*string
ptr := &house
// 打印ptr的類型
fmt.Printf("ptr type: %T\n", ptr)
// 打印ptr的指針地址
fmt.Printf("address: %p\n", ptr)
// 對(duì)指針進(jìn)行取值操作
value := *ptr
// 取值后的類型
fmt.Printf("value type: %T\n", value)
// 指針取值后就是指向變量的值
fmt.Printf("value: %s\n", value)
}運(yùn)行結(jié)果:
ptr type: *string
address: 0xc0420401b0
value type: string
value: Malibu Point 10880, 90265
代碼說(shuō)明如下:
- 第 10 行,準(zhǔn)備一個(gè)字符串并賦值。
- 第 13 行,對(duì)字符串取地址,將指針保存到變量 ptr 中。
- 第 16 行,打印變量 ptr 的類型,其類型為 *string。
- 第 19 行,打印 ptr 的指針地址,地址每次運(yùn)行都會(huì)發(fā)生變化。
- 第 22 行,對(duì) ptr 指針變量進(jìn)行取值操作,變量 value 的類型為 string。
- 第 25 行,打印取值后 value 的類型。
- 第 28 行,打印 value 的值。
取地址操作符
&和取值操作符
*是一對(duì)互補(bǔ)操作符,
&取出地址,
*根據(jù)地址取出地址指向的值。
變量、指針地址、指針變量、取地址、取值的相互關(guān)系和特性如下:
- 對(duì)變量進(jìn)行取地址操作使用
&操作符,可以獲得這個(gè)變量的指針變量。 - 指針變量的值是指針地址。
- 對(duì)指針變量進(jìn)行取值操作使用
*操作符,可以獲得指針變量指向的原變量的值。
使用指針修改值
通過(guò)指針不僅可以取值,也可以修改值。
前面已經(jīng)演示了使用多重賦值的方法進(jìn)行數(shù)值交換,使用指針同樣可以進(jìn)行數(shù)值交換,代碼如下:
package main
import "fmt"
// 交換函數(shù)
func swap(a, b *int) {
// 取a指針的值, 賦給臨時(shí)變量t
t := *a
// 取b指針的值, 賦給a指針指向的變量
*a = *b
// 將a指針的值賦給b指針指向的變量
*b = t
}
func main() {
// 準(zhǔn)備兩個(gè)變量, 賦值1和2
x, y := 1, 2
// 交換變量值
swap(&x, &y)
// 輸出變量值
fmt.Println(x, y)
}運(yùn)行結(jié)果:
2 1
代碼說(shuō)明如下:
- 第 6 行,定義一個(gè)交換函數(shù),參數(shù)為 a、b,類型都為 *int 指針類型。
- 第 9 行,取指針 a 的值,并把值賦給變量 t,t 此時(shí)是 int 類型。
- 第 12 行,取 b 的指針值,賦給指針 a 指向的變量。注意,此時(shí)
*a的意思不是取 a 指針的值,而是“a 指向的變量”。 - 第 15 行,將 t 的值賦給指針 b 指向的變量。
- 第 21 行,準(zhǔn)備 x、y 兩個(gè)變量,分別賦值為 1 和 2,類型為 int。
- 第 24 行,取出 x 和 y 的地址作為參數(shù)傳給 swap() 函數(shù)進(jìn)行調(diào)用。
- 第 27 行,交換完畢時(shí),輸出 x 和 y 的值。
*操作符作為右值時(shí),意義是取指針的值,作為左值時(shí),也就是放在賦值操作符的左邊時(shí),表示 a 指針指向的變量。其實(shí)歸納起來(lái),
*操作符的根本意義就是操作指針指向的變量。當(dāng)操作在右值時(shí),就是取指向變量的值,當(dāng)操作在左值時(shí),就是將值設(shè)置給指向的變量。
如果在 swap() 函數(shù)中交換操作的是指針值,會(huì)發(fā)生什么情況?可以參考下面代碼:
package main
import "fmt"
func swap(a, b *int) {
b, a = a, b
}
func main() {
x, y := 1, 2
swap(&x, &y)
fmt.Println(x, y)
}運(yùn)行結(jié)果:
1 2
結(jié)果表明,交換是不成功的。上面代碼中的 swap() 函數(shù)交換的是 a 和 b 的地址,在交換完畢后,a 和 b 的變量值確實(shí)被交換。但和 a、b 關(guān)聯(lián)的兩個(gè)變量并沒(méi)有實(shí)際關(guān)聯(lián)。這就像寫(xiě)有兩座房子的卡片放在桌上一字?jǐn)傞_(kāi),交換兩座房子的卡片后并不會(huì)對(duì)兩座房子有任何影響。
示例:使用指針變量獲取命令行的輸入信息
Go語(yǔ)言內(nèi)置的 flag 包實(shí)現(xiàn)了對(duì)命令行參數(shù)的解析,flag 包使得開(kāi)發(fā)命令行工具更為簡(jiǎn)單。
下面的代碼通過(guò)提前定義一些命令行指令和對(duì)應(yīng)的變量,并在運(yùn)行時(shí)輸入對(duì)應(yīng)的參數(shù),經(jīng)過(guò) flag 包的解析后即可獲取命令行的數(shù)據(jù)。
【示例】獲取命令行輸入:
package main
// 導(dǎo)入系統(tǒng)包
import (
"flag"
"fmt"
)
// 定義命令行參數(shù)
var mode = flag.String("mode", "", "process mode")
func main() {
// 解析命令行參數(shù)
flag.Parse()
// 輸出命令行參數(shù)
fmt.Println(*mode)
}將這段代碼命名為 main.go,然后使用如下命令行運(yùn)行:
go run main.go --mode=fast
命令行輸出結(jié)果如下:
fast
代碼說(shuō)明如下:
- 第 10 行,通過(guò) flag.String,定義一個(gè) mode 變量,這個(gè)變量的類型是 *string。后面 3 個(gè)參數(shù)分別如下:
- 參數(shù)名稱:在命令行輸入?yún)?shù)時(shí),使用這個(gè)名稱。
- 參數(shù)值的默認(rèn)值:與 flag 所使用的函數(shù)創(chuàng)建變量類型對(duì)應(yīng),String 對(duì)應(yīng)字符串、Int 對(duì)應(yīng)整型、Bool 對(duì)應(yīng)布爾型等。
- 參數(shù)說(shuō)明:使用 -help 時(shí),會(huì)出現(xiàn)在說(shuō)明中。
- 第 15 行,解析命令行參數(shù),并將結(jié)果寫(xiě)入到變量 mode 中。
- 第 18 行,打印 mode 指針?biāo)赶虻淖兞俊?/li>
由于之前已經(jīng)使用 flag.String 注冊(cè)了一個(gè)名為 mode 的命令行參數(shù),flag 底層知道怎么解析命令行,并且將值賦給 mode*string 指針,在 Parse 調(diào)用完畢后,無(wú)須從 flag 獲取值,而是通過(guò)自己注冊(cè)的這個(gè) mode 指針獲取到最終的值。代碼運(yùn)行流程如下圖所示。
圖:命令行參數(shù)與變量的關(guān)系
創(chuàng)建指針的另一種方法——new() 函數(shù)
Go語(yǔ)言還提供了另外一種方法來(lái)創(chuàng)建指針變量,格式如下:
new(類型)
一般這樣寫(xiě):
str := new(string) *str = "Go語(yǔ)言教程" fmt.Println(*str)
new() 函數(shù)可以創(chuàng)建一個(gè)對(duì)應(yīng)類型的指針,創(chuàng)建過(guò)程會(huì)分配內(nèi)存,被創(chuàng)建的指針指向默認(rèn)值。
本文標(biāo)題:創(chuàng)新互聯(lián)GO教程:Go語(yǔ)言指針詳解,看這一篇文章就夠了
標(biāo)題URL:http://www.5511xx.com/article/dpoopic.html


咨詢
建站咨詢
