主要區(qū)分一下兩個(gè)方面的內(nèi)容:
- 單純的方法定義
- 通過(guò)接口傳遞參數(shù)
1避诽、 單純的方法定義
go語(yǔ)言內(nèi)部會(huì)自動(dòng)進(jìn)行值和指針的轉(zhuǎn)換, 代碼在編譯的時(shí)候不會(huì)出錯(cuò);區(qū)別在于使用指針定義方法璃谨,方法操作的是該數(shù)據(jù)本身沙庐;而使用值定義方法時(shí),方法操作的是該數(shù)據(jù)的拷貝佳吞。
總結(jié):如果使用除接口類型以外的類型作為接收者時(shí)拱雏,使用值和指針調(diào)用方法不會(huì)出現(xiàn)編譯錯(cuò)誤; 如果使用接口類型的變量(實(shí)現(xiàn)了該接口)調(diào)用方法時(shí)底扳,使用值調(diào)用指針定義的方法時(shí)會(huì)出現(xiàn)編譯出錯(cuò)铸抑。
1、 使用值定義方法衷模,使用值調(diào)用方法的情況
type user struct {
name string
email string
}
func (u user) notify() {
//將傳入的參數(shù)復(fù)制一份鹊汛,賦值給u
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
輸出(名子并不會(huì)改變):
Send email to Jack 1139329@163.com
{Andy 1139329@163.com}
2、 使用值定義方法阱冶,使用指針調(diào)用方法的情況
由于定義方法時(shí)使用的是值刁憋,在編譯過(guò)程中會(huì)對(duì)調(diào)用者為指針的類型進(jìn)行解引用,內(nèi)部實(shí)現(xiàn)為 *user.notify()
type user struct {
name string
email string
}
func (u user) notify() {
//將傳入的參數(shù)復(fù)制一份木蹬,賦值給u
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := &user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
輸出(名子也不會(huì)改變):
Send email to Jack 1139329@163.com
{Andy 1139329@163.com}
3至耻、 使用指針定義方法,使用指針調(diào)用方法的情況
type user struct {
name string
email string
}
func (u *user) notify() {
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
輸出(名子會(huì)改變):
Send email to Jack 1139329@163.com
{Jack 1139329@163.com}
4、 使用指針定義方法尘颓,使用值調(diào)用方法的情況
內(nèi)部實(shí)現(xiàn)為 *user.notify()
type user struct {
name string
email string
}
func (u *user) notify() {
u.name = "Jack"
fmt.Println("Send email to", u.name, u.email)
}
func main() {
user := user{"Andy", "1139329@163.com"}
user.notify()
fmt.Println(user)
}
輸出(名子會(huì)改變):
Send email to Jack 1139329@163.com
{Jack 1139329@163.com}
2是尖、 通過(guò)接口傳遞參數(shù)
1、 接受者receiver為值泥耀,使用值傳遞的情況
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//編譯成功
2、 接受者receiver為值蛔添,使用指針傳遞的情況
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := &user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//編譯成功
3痰催、 接受者receiver為指針,使用指針傳遞的情況
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u *user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := &user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//編譯成功
4迎瞧、 接受者receiver為指針夸溶,使用值傳遞的情況
type user struct {
name string
email string
}
type notifyInterface interface {
notify()
}
func (u *user) notify() {
fmt.Println("Send email to", u.name, u.email)
}
func sendNotification(n notifyInterface) {
n.notify()
}
func main() {
user := user{"Andy", "1139329@163.com"}
sendNotification(user)
}
//編譯失敗(使用指針接受者來(lái)實(shí)現(xiàn)一個(gè)接口凶硅,值類型無(wú)法實(shí)現(xiàn)對(duì)應(yīng)的接口)
cannot use user (type user) as type notifyInterface in argument to sendNotification:
user does not implement notifyInterface (notify method has pointer receiver)
針對(duì)以上情況缝裁,《Go語(yǔ)言實(shí)戰(zhàn)》一書(shū)中這樣講到,首先這是Go語(yǔ)言的一種規(guī)則足绅,具體如下:如果使用指針接受者來(lái)實(shí)現(xiàn)一個(gè)接口捷绑,那么只有指向那個(gè)類型的指針才能夠實(shí)現(xiàn)對(duì)應(yīng)的接口。如果使用值接受者來(lái)實(shí)現(xiàn)一個(gè)接口氢妈,那么那個(gè)類型的值和指針都能夠實(shí)現(xiàn)對(duì)應(yīng)的接口粹污。
為什么會(huì)有這樣的限制呢:作者解釋為go編譯器并不總能自動(dòng)獲得一個(gè)值得地址!