前言
值型別:所有像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...