南昌那個公司做網(wǎng)站好今日最新國際新聞頭條
目錄
一.引言
二.接收者類型
三.代碼示例
1.指針接收者
2.值接收者
3.運行結(jié)果對比
4.代碼修改
5.刨根問底
四.總結(jié)
一.引言
go 語言中 func (c *Title) 和 func (c Title) 兩個方法的傳參差一個 * 號,二者的區(qū)別是一個是指針類型,一個是值類型,下面我們簡單整理下二者在 Func 中的差異和使用示例。
二.接收者類型
-
指針接收者 (
*Type
):- 當方法的接收者是指針類型時,方法可以修改接收者指向的對象的狀態(tài)。
- 由于指針接收者可以避免復制整個對象,因此適合用于較大的結(jié)構(gòu)體。
- 可以通過指針調(diào)用方法,或通過值調(diào)用方法,Go 會自動將值的地址傳遞給指針接收者。
-
值接收者 (
Type
):- 當方法的接收者是值類型時,方法接收者的值是通過值復制傳遞的,因此方法內(nèi)部對接收者的任何修改不會影響到原始對象。
- 適合用于小型結(jié)構(gòu)體或者值不變的方法。
- 只有值調(diào)用方法時才會調(diào)用值接收者的方法,不能通過指針調(diào)用該方法。
三.代碼示例
1.指針接收者
package mainimport "fmt"// 定義結(jié)構(gòu)體
type Title struct {title string
}// 使用指針接收者的方法
func (c *Title) SetTitle(title string) {c.title = title
}// 使用指針接收者的方法
func (c *Title) GetTitle() string {return c.title
}func main() {advisor := Title{}// 調(diào)用 SetTitle 方法(通過值調(diào)用)-- Go 會自動將地址傳遞給指針接收者advisor.SetTitle("New Title")// 調(diào)用 GetTitle 方法獲取設(shè)置后的值fmt.Println(advisor.GetTitle())
}
2.值接收者
package mainimport "fmt"// 定義結(jié)構(gòu)體
type Title struct {title string
}// 使用值接收者的方法
func (c Title) SetTitle(title string) {c.title = title
}// 使用值接收者的方法
func (c Title) GetTitle() string {return c.title
}func main() {advisor := Title{}// 調(diào)用 SetTitle 方法(通過值調(diào)用)advisor.SetTitle("New Title")// 調(diào)用 GetTitle 方法fmt.Println(advisor.GetTitle())
}
3.運行結(jié)果對比
- 在第一種情況下(指針接收者),調(diào)用?
SetTitle
?后,GetTitle
?會返回?"New Title"
,因為?SetTitle
?方法修改了?title
?字段。 - 在第二種情況下(值接收者),調(diào)用?
SetTitle
?后,GetTitle
?仍然會返回空字符串?""
,因為?SetTitle
?方法修改的是?advisor
?的副本,而不是原始對象。
4.代碼修改
下面我們對值接收者代碼做簡單修改,使得我們 GetTitle 方法可以獲得結(jié)果,由于值類型只能獲取原始結(jié)構(gòu)的信息,無法修改信息,所以 SetTitle 這里是不生效的,如果想要獲取 title,我們在初始化結(jié)構(gòu)體的時候就定義好 title 的值,這樣就可以獲取了。
package mainimport "fmt"// 定義結(jié)構(gòu)體
type Title struct {title string
}// 使用值接收者的方法
func (c Title) SetTitle(title string) {c.title = title
}// 使用值接收者的方法
func (c Title) GetTitle() string {return c.title
}func main() {advisor := Title{}advisor.title = "New Title V2"// 調(diào)用 SetTitle 方法(通過值調(diào)用)advisor.SetTitle("New Title")// 調(diào)用 GetTitle 方法fmt.Println(advisor.GetTitle())
}
5.刨根問底
advisor := Title{}advisor.title = "New Title V2"
Q: 上面我們通過下述方法為 Title 類設(shè)置了標題,按照上面的思維,能夠修改變量,那這里 advisor 是指針還是值呢??
A: advisor
?不是指針,而是一個?Title
?結(jié)構(gòu)體類型的實例。這個實例是值類型的,而不是指針類型的。
值類型
當使用?Title{}
?初始化結(jié)構(gòu)體實例時,產(chǎn)生的是一個值類型的變量。這意味著?advisor
?變量直接存儲結(jié)構(gòu)體實例的數(shù)據(jù)。
package mainimport "fmt"type Title struct {title string
}func main() {// 初始化結(jié)構(gòu)體實例,advisor 是 Title 類型的值advisor := Title{}// 設(shè)置字段值advisor.title = "New Title V2"// 輸出fmt.Println(advisor.title) // 輸出: New Title V2
}
指針類型
如果需要得到一個指針類型,可以使用?&
?操作符,這樣?advisor
?變量將是一個指向?Title
?結(jié)構(gòu)體實例的指針。
func main() {// 初始化結(jié)構(gòu)體實例,并獲取其指針advisor := &Title{}// 通過指針來設(shè)置字段值advisor.title = "New Title V2"// 輸出fmt.Println(advisor.title) // 輸出: New Title V2
}
上面兩個方法都會輸出 "New Title V2",這里如果單純構(gòu)建結(jié)構(gòu)體 Title 的話, Title 和 &TItle 是一樣的,它們在初始化結(jié)構(gòu)體實例方面并沒有區(qū)別。顯著的區(qū)別在于將實例傳遞到函數(shù)中時的行為。
package mainimport "fmt"type Title struct {title string
}func main() {// 值類型advisorValue := Title{}advisorValue.title = "ddd"fmt.Println("Value Type:", advisorValue.title)// 指針類型advisorPointer := &Title{}advisorPointer.title = "ddd"fmt.Println("Pointer Type:", advisorPointer.title)
}
上面兩個方法達到的需求是一樣的,那實際場景中我們該寫哪種呢?
簡單和小型結(jié)構(gòu)體:
如果你的結(jié)構(gòu)體很簡單并且字段比較少(如本例中的 Title 結(jié)構(gòu)體),且多數(shù)情況下僅做讀取操作,使用值類型創(chuàng)建可以更加直觀和簡單。
推薦使用值類型:advisorValue := Title{}
修改結(jié)構(gòu)體數(shù)據(jù):
如果你的代碼需要在多個函數(shù)中修改結(jié)構(gòu)體字段,使用指針類型可以避免復制整個結(jié)構(gòu)體,有助于提高性能。
推薦使用指針類型:advisorPointer := &Title{}
一致性:
如果整個代碼庫中大多數(shù)情況下都需要頻繁對結(jié)構(gòu)體進行修改,使用指針類型可以保持一致性,避免混淆。在這種情況下,可以統(tǒng)一使用指針類型。
我們上面的示例中,如果 title 寫死了只做讀取,那我們就 := Title,如果我們需要頻繁修改 title 值,就是用 := &Title。
四.總結(jié)
- 指針接收者?用于需要修改接收者內(nèi)部狀態(tài)的方法,并且適合較大的結(jié)構(gòu)體實例。
- 值接收者?用于不需要修改內(nèi)部狀態(tài)的方法,只適用于小型結(jié)構(gòu)體或方法調(diào)用時不涉及修改操作。
選擇使用指針接收者還是值接收者取決于您的具體需求和結(jié)構(gòu)體的大小。對于需要修改內(nèi)部狀態(tài)、傳遞較大結(jié)構(gòu)體的情況,推薦使用指針接收者。對于不修改狀態(tài)的情況,可以使用值接收者。