golang中值型別 指標型別的變數區別總結

2022-09-28 09:12:10 字數 3792 閱讀 3959

前言

值型別:所有像int、float、bool和string這些型別都屬於值型別,使用這些型別的變數直接指向存在記憶體中的值,值型別的變數的值儲存在棧中。當使用等號=將乙個變數的值賦給另乙個變數時,如 j = i ,實際上是在記憶體中將 i 的值進行了拷貝。可以通過 &i 獲取變數 i 的記憶體位址

指標型別:簡單地說go語言的指標型別和c/c++的指標型別用法是一樣的,除了出去安全性的考慮,go語言增加了一些限制,包括如下幾條:

下面將給大家詳細介紹golang中值型別/指標型別的變數的一些區別,下面話不多說了,來一起看看詳細的介紹吧。

值型別的變數和指標型別的變數

先宣告乙個結構體:

type t struct

func (t t) m1()

func (t *t) m2()

m1()的接收者是值型別 t,m2()的接收者是值型別 *t , 兩個方法內都是改變name值。

下面宣告乙個 t 型別的變數,並呼叫m1()和m2()。

t1 := t

fmt.println("m1呼叫前:", t1.name)

t1.m1()

fmt.println("m1呼叫後:", t1.name)

fmt.println("m2呼叫前:", t1.name)

t1.m2()

fmt.println("m2呼叫後:", t1.name

輸出結果為:

m1呼叫前: t1

m1呼叫後: t1

m2呼叫前: t1

m2呼叫後: name2

下面猜測一下go會怎麼處理。

先來約定一下:接收者可以看作是函式的第乙個引數,即這樣的:func m1(t t),func m2(t *t)。 go不是物件導向的語言,所以用那種看起來像物件導向的語法來理解可能有偏差。

當呼叫t1.m1()時相當於m1(t1),實參和行參都是型別 t,可以接受。此時在m1()中的t只是t1的值拷貝,所以m1()的修改影響不到t1。

當呼叫t1.m2() => m2(t1),這是將 t 型別傳給了 *t 型別,go可能會取 t1 的位址傳進去:m2(&t1)。所以m2()的修改可以影響 t1 。

型別的變數這兩個方法都是擁有的。

下面宣告乙個 *t 型別的變數,並呼叫m1()和m2()。

t2 := &t

fmt.println("m1呼叫前:", t2.name)

t2.m1()

fmt.println("m1呼叫後:", t2.name)

fmt.println("m2呼叫前:", t2.na

t2.m2()

fmt.println("m2呼叫後:", t2.name)

輸出結果為:

m1呼叫前: t2

m1呼叫後: t2

m2呼叫前: t2

m2呼叫後: name2

t2.m1() => m1(t2), t2 是指標型別, 取 t2 的值並拷貝乙份傳給 m1。

t2.m2() => m2(t2),都是指標型別,不需要轉換。

*t 型別的變數也是擁有這兩個方法的。

傳給介面會怎樣?

先宣告乙個介面

type intf inte***ce

使用:var t1 t = t

t1.m1()

t1.m2()

var t2 intf = t1

t2.m1()

t2.m2()

報錯:./main.go:9: cannot use t1 (type t) as type intf in assignment:

t does not implement intf (m2 method has pointer receiver)

var t2 intf = t1這一行報錯。

t1 是有m2()方法的,但是為什麼傳給 t2 時傳不過去呢?

簡單來說,按照介面的理論:傳過去【賦值】的物件必須實現了介面要求的方法,而t1沒有實現m2(),t1的指標實現了m2()。另外和c語言一樣,函式名本身就是指標

當把var t2 intf = t1修改為var t2 intf = &t1時編譯通過,此時 t2 獲得的是 t1 的位址,t2.m2()的修改可以影響到 t1 了。

如果宣告乙個方法 func f(t intf), 引數的傳遞和上面的直接賦值是一樣的情況。

巢狀型別

宣告乙個型別 s,將 t 嵌入進去

type s struct

使用下面的例子測試一下:

t1 := t

s :程式設計客棧= s

fmt.println("m1呼叫前:", s.name)

s.m1()

fmt.println("m1呼叫後:", s.name)

fmt.println("m2呼叫前:", s.name)

s.m2()

fmt.println("m2呼叫後:", s.name)

fmt.println(t1.name)

輸出:m1呼叫前: t1

m1呼叫後: t1

m2呼叫前: t1

m2呼叫後: name2

t1將 t 嵌入 s, 那麼 t 擁有的方法和屬性 s 也是擁有的,但是接收者卻不是 s 而是 www.cppcns.comt。

所以s.m1()相當於m1(t1)而不是m1(s)。

最後 t1 的值沒有改變,因為我們嵌入的是 t 型別,所以 s 的時候是將 t1 拷貝了乙份。

假如我們將 s 賦值給 intf 介面會怎麼樣呢?

var intf intf = s

intf.m1()

intf.m2()

報錯:cannot use s (type s) as type intf in assignment: s does not implement intf (m2 method has pointer receiver)

還是m2()的問題,因為 s 此時還是值型別。

var intf intf = &s這樣的話編譯通過了,如果在intf.m2()中改變了 name 的值,s.name被改變了,但是t1.name依然沒變,因為現在 t1 和 s 已經沒有聯絡了。

下面嵌入 *t 試試:

type s struct

使用時這樣:

t1 := t

s := s

fmt.println("m1呼叫前:", s.name)

s.m1()

fmt.println("m1呼叫後:", s.name)

fmt.println("m2呼叫前:", s.name)

s.m2()

fmt.println("m2呼叫後:", s.name)

fmt.println(t1.name)

m1呼叫前: t1

m1呼叫後: t1

m2呼叫前: t1

m2呼叫後: name2

name2

惟一的區別是最後 t1 的值變了,因為我們複製的是指標。

接著賦值給介面試試:

var intf intf = s i

ntf.m1()

intf.m2()

fmt.println(s.name)

編譯沒有報錯。這裡我們傳遞給 intf 的是值型別而不是指標,為什麼可以通過呢?

拷貝 s 的時候裡面的 t 是指標型別,所以呼叫m2()的時候傳遞進去的是乙個指標。

var intf intf = &s的效果和上面一樣。

總結本文標題: golang中值型別/指標型別的變數區別總結

本文位址: /jiaoben/golang/213844.html

golang 指標型別學習

對於指標型別不安全程式設計,通過指標值以及偏移量操作slice私有屬性 通過指標值獲取切片 func testgetprivate t testing.t sptr uintptr unsafe.pointer s 獲取當前結構體例項的指標值 t.log sptr arrptr int unsafe...

Golang 複雜型別的指標

在go語言中,沒有最複雜的指標運算的部分,只留下了獲取指標 運算子 和獲取物件 運算子 的運算 a,b 3,5 pa,pb a,b fmt.println pa,pb 對於一些複雜型別的指標,如果要訪問成員變數的話,需要寫成類似 p field的形式,go提供了隱式解引用特性,我們只需要p.fiel...

golang 指標型別和普通型別的方法集

用例項value與pointer呼叫方法 含匿名字段 不受方法集的約束,編譯器總是查詢全部方法,並且自動轉換receiver實參 package main import fmt type person struct 非指標 func p person setinfovalue 指標 func p p...