日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

go语言的指针类型

發(fā)布時間:2023/12/15 综合教程 24 生活家
生活随笔 收集整理的這篇文章主要介紹了 go语言的指针类型 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、指針與引用的相關(guān)概念

什么是指針?

  指針,全稱為指針變量,是用來存儲內(nèi)存地址的一種變量。程序中,一般通過指針來訪問其指向的內(nèi)存地址中的內(nèi)容(數(shù)據(jù))。

什么是引用?

  引用,是C++中提出來的一種新的使用變量的方式,即,給實際變量起個別名,通過這個別名來引用實際的變量。標(biāo)準(zhǔn)C中不支持變量的引用。

指針與引用的區(qū)別?

  1.指針是實實在在的變量,有自己的內(nèi)存存儲空間,它可以指向任何有效的變量。

  2.引用是一種形式、方法,定義的引用變量,實際上是原實際變量的另一個名稱(別名),引用變量本身沒有自己的實際存儲空間,操作引用變量,就是在操作實際變量。

go語言的指針與c語言指針,以及java,python等引用類型的語言的區(qū)別與聯(lián)系:

  1.Java,Python,Javascript 等引用類型的語言

  2.Golang 的指針是單獨(dú)的類型,而不是 C 語言中的 int 類型,而且也不能對指針做整數(shù)運(yùn)算。

  3.從這一點(diǎn)看,Golang 的指針基本就是一種引用。

對引用類型語言來說,參數(shù)傳遞時,什么時候傳值,什么時候傳引用?

  1.在大部分引用型語言里,參數(shù)為基本類型時,傳進(jìn)去的大都是值,也就是另外復(fù)制了一份參數(shù)到當(dāng)前的函數(shù)調(diào)用棧。

  2.參數(shù)為高級類型時,傳進(jìn)去的基本都是引用。這個主要是因為虛擬機(jī)的內(nèi)存管理導(dǎo)致的。

傳值和傳引用的區(qū)別?

  1.內(nèi)存管理中的內(nèi)存區(qū)域一般包括 heap 和 stack, stack 主要用來存儲當(dāng)前調(diào)用棧用到的簡單類型數(shù)據(jù):string,boolean,int,float 等。

  2.這些類型的內(nèi)存占用小,容易回收,基本上它們的值和指針占用的空間差不多,因此可以直接復(fù)制,GC也比較容易做針對性的優(yōu)化。

  3.復(fù)雜的高級類型占用的內(nèi)存往往相對較大,存儲在 heap 中,GC 回收頻率相對較低,代價也較大,因此傳引用/指針可以避免進(jìn)行成本較高的復(fù)制操作,并且節(jié)省內(nèi)存,提高程序運(yùn)行效率。

而在 Golang 中,具體到高級類型 struct,slice,map,也各有不同。實際上,只有 struct 的使用有點(diǎn)復(fù)雜,slice,map,chan 都可以直接使用,不用考慮是值還是指針。

二、go語言指針介紹

go的原生數(shù)據(jù)類型分類:

  1.基本類型:string, bool, int, float等 使用值傳遞

  2.高級類型:sturuct, array/slice, map, chan, func。 使用引用傳遞

go的指針定義:

  a.一個指針的值是另一個變量的地址。

  b.一個指針對應(yīng)變量在內(nèi)存中的存儲位置。

  c.并不是每一個值都會有一個內(nèi)存地址。

  d.滅一個變量必然有對應(yīng)的內(nèi)存地址?!   ?/p>

  e.用過指針我們可以直接讀或者更新對應(yīng)變量的值,而不需要知道該變量的名字。

go語言中,什么時候使用指針?(指針使用的場景):

  1.需要改變參數(shù)的值

  2.避免復(fù)制操作

  3.節(jié)省內(nèi)存

go語言的值傳遞和“引用傳遞”

  1.go語言中的傳遞方式只有值傳遞

  2.所謂的“引用傳遞”是指將要傳遞的較大的值,復(fù)制他的內(nèi)存地址然后將內(nèi)存地址通過值傳遞傳給對象。對象拿到內(nèi)存地址的值就可以直接訪問了。這個過程看起來很像“引用傳遞”

指針(pointer)在go 語言中拆分為兩個核心概念:

  1.類型指針,允許對這個指針類型的數(shù)據(jù)進(jìn)行修改。傳遞數(shù)據(jù)使用指針,而無需拷貝數(shù)據(jù)。類型指針不能進(jìn)行偏移量和運(yùn)算。

  2.切片,由指向起始元素的原始指針、元素數(shù)量和容量組成。

go語言指針的優(yōu)勢:

  1.Go 語言的指針類型變量擁有指針的高效訪問

  2.不會發(fā)生指針偏移,從而避免非法修改關(guān)鍵性數(shù)據(jù)問題。

  3.垃圾回收也比較容易對不會發(fā)生偏移的指針進(jìn)行檢索和回收。

  4.切片比原始指針具備更強(qiáng)大的特性,更為安全。

  5.切片發(fā)生越界時,運(yùn)行時會報出宕機(jī),并打出堆棧,而原始指針只會崩潰。

指針類型和指針地址:

  1.每個變量在運(yùn)行時都擁有一個地址,這個地址代表變量在內(nèi)存中的位置

  2.Go 語言中使用&作符放在變量前面對變量進(jìn)行“取地址”操作。

ptr := &v    // v的類型為T

  v 代表被取地址的變量

  變量prt 接收 被取地址的 v

  ptr 的類型就為*T,稱做 T 的指針類型。*代表指針。

package main
import (
    "fmt"
)
func main() {
    //聲明整型 cat 變量。
    var cat int = 1
    //聲明字符串 str 變量。
    var str string = "banana"
   //使用 fmt.Printf 的動詞%p輸出 cat 和 str 變量取地址后的指針值,指針值帶有0x的十六進(jìn)制前綴。
    fmt.Printf("%p %p", &cat, &str)
}



//運(yùn)行結(jié)果
//0xc042052088 0xc0420461b0

指針的實際用法

變量、指針、地址,三者的關(guān)系?

  1.每個變量都擁有地址

  2.指針的值就是地址

  

如何使用指針獲取指針指向的值?

  在對普通變量使用&操作符取地址獲得這個變量的指針后,可以對指針使用*操作,也就是指針取值

package main
import (
    "fmt"
)
func main() {
    // 準(zhǔn)備一個字符串類型
    var house = "Malibu Point 10880, 90265"
    // 對字符串取地址, 將指針保存到 ptr 中,ptr類型為*string
    ptr := &house
    // 打印ptr的類型  類型為 *string。
    fmt.Printf("ptr type: %T
", ptr)
    // 打印ptr的指針地址   每次運(yùn)行都會發(fā)生變化。
    fmt.Printf("address: %p
", ptr)
    // 對 ptr 指針變量進(jìn)行取值操作   value 變量類型為 string。
    value := *ptr
    // 取值后的類型
    fmt.Printf("value type: %T
", value)
    // 指針取值后就是指向變量的值
    fmt.Printf("value: %s
", value)
}


//運(yùn)行結(jié)果
//ptr type: *string
//address: 0xc0420401b0
//value type: string
//value: Malibu Point 10880, 90265

指針獲取指針

  取地址操作符&和取值操作符*是一對互補(bǔ)操作符

  &取出地址,*根據(jù)地址取出地址指向的值。

變量、指針地址、指針變量、取地址、取值的相互關(guān)系和特性:

  1.對變量進(jìn)行取地址(&)操作,可以獲得這個變量的指針變量。

  2.指針變量的值是指針地址。

  3.對指針變量進(jìn)行取值(*)操作,可以獲得指針變量指向的原變量的值。

指針的零值和相等測試

  1.任何類型的指針的零值都是nil。

  2.如果 p != nil 為真,那么p就指向某個有效變量 (p為指針)

  3.指針只有指向同一個變量或者全部為nil時才相等。

var x,y int
var z  *int
var w  *string
fmt.Println(&x ==&x, &x ==&y,&x ==nil , z == nil ,  w ==nil)

//true false false true true

指針的相等測試

如何使用指針修改值?

package main
import "fmt"
// 定義一個交換函數(shù),參數(shù)為 a、b,類型都為 *int,都是指針類型。
func swap(a, b *int) {
    // 將 a 指針取值,把值(int類型)賦給 t 變量,t 此時也是 int 類型。
    t := *a
    // 取 b 指針值,賦給 a 變量指向的變量。注意,此時*a的意思不是取 a 指針的值,而是“a指向的變量”。
    *a = *b
    // 將 t 的值賦給 b 指向的變量。
    *b = t
}
func main() {
// 準(zhǔn)備 x、y 兩個變量,賦值 1 和 2,類型為 int。
    x, y := 1, 2
    // 取出 x 和 y 的地址作為參數(shù)傳給 swap() 函數(shù)進(jìn)行調(diào)用。
    swap(&x, &y)
    // 交換完畢時,輸出 x 和 y 的值。
    fmt.Println(x, y)
}


//運(yùn)行結(jié)果
//2 1

使用指針修改值

  1.*操作符作為右值時,意義是取指針的值

  2.作為左值時,也就是放在賦值操作符的左邊時,表示 a 指向的變量。

  歸納:

    1.*操作符的根本意義就是操作指針指向的變量。

    2.當(dāng)操作在右值時,就是取指向變量的值;

    3.當(dāng)操作在左值時,就是將值設(shè)置給指向的變量。

  每次我們對一個變量取地址,或者是復(fù)制指針,我們都是為原變量創(chuàng)建新的別名。例如a就是變量p的別名。

  指針特別有價值的地方在于我們可以不用名字而訪問一個變量的?! ?/p>

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

swap() 函數(shù)中交換指針值

  1.上面代碼中的 swap() 函數(shù)交換的是 a 和 b 的地址

  2.在交換完畢后,a 和 b 的變量值確實被交換。

  3.但和 a、b 關(guān)聯(lián)的兩個變量并沒有實際關(guān)聯(lián)。

  4.這就像寫有兩座房子的卡片放在桌上一字?jǐn)傞_,交換兩座房子的卡片后并不會對兩座房子有任何影響。

創(chuàng)建指針的另一種方法--new()函數(shù)

package main

import "fmt"


func main() {
    //申請一個指針str,類型為*string
    str := new(string)
        //指針str指向字符串“ninja”
    *str = "ninja"
        //打印str指向的地址空間
    fmt.Println(*str)
        //打印指針str的內(nèi)存地址
    fmt.Printf("%p
",str)
    fmt.Printf("%d
",str)
        //打印指針str的類型
    fmt.Printf("%T
",str)

}


//運(yùn)行結(jié)果
//ninja
//0xc00000e1e0
//824633778656
//*string

new()方法創(chuàng)建指針

總結(jié)

以上是生活随笔為你收集整理的go语言的指针类型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。