go中方法的接收者是值或者指標有什麼區別嗎?

2021-07-02 04:05:47 字數 4151 閱讀 9172

參考文章:

假設有兩個方法,乙個方法的接收者是指標型別,乙個方法的接收者是值型別,那麼:

先宣告乙個結構體:

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 型別的變數這兩個方法都是擁有的。

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

t2 := &t

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

t2.m1()

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

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

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

haspointer

receiver)

var t2 intf = t1這一行報錯。

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

t1 是值型別,賦值給 t2 時是複製值而不是指標,假設 t1 可以賦值給 t2, t2.m2() 修改 name 的值時也是修改的拷貝的變數,無法影響到 t1,那把 t1 賦值給 t2 還有什麼意義呢?所以這種賦值是不被允許的。

當把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 而是 t。

所以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

haspointer

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)

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

接著賦值給介面試試:

var intf intf = s

intf.m1()

intf.m2()

fmt.println(s.name)

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

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

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

go中方法的接收者是值或者指標的區別

先宣告乙個結構體 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 ...

Go值接收者方法和指標接收者方法

go語言有值型別和指標型別直接呼叫其值接收者方法和指標接收者方法的區別 先看乙個例項 package main import fmt type ifather inte ce type person struct func p person getname string func p person ...

Go 值接收者和指標接收者 區別

首先回顧一下go語言值型別和指標型別直接呼叫其值接收者方法和指標接收者方法的區別 先看乙個例項 package main import fmt type i inte ce type s struct func s s get int func s s set age int func main f...