主要區(qū)分一下兩個方面的內(nèi)容:
- 單純的方法定義
- 通過接口傳遞參數(shù)
1、 單純的方法定義
go語言內(nèi)部會自動進行值和指針的轉(zhuǎn)換, 代碼在編譯的時候不會出錯;區(qū)別在于使用指針定義方法,方法操作的是該數(shù)據(jù)本身;而使用值定義方法時,方法操作的是該數(shù)據(jù)的拷貝。
總結(jié):如果使用除接口類型以外的類型作為接收者時,使用值和指針調(diào)用方法不會出現(xiàn)編譯錯誤; 如果使用接口類型的變量(實現(xiàn)了該接口)調(diào)用方法時,使用值調(diào)用指針定義的方法時會出現(xiàn)編譯出錯。
1、 使用值定義方法,使用值調(diào)用方法的情況
type user struct {
name string
email string
}
func (u user) notify() {
//將傳入的參數(shù)復制一份,賦值給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)
}
輸出(名子并不會改變):
Send email to Jack 1139329@163.com
{Andy 1139329@163.com}
2、 使用值定義方法,使用指針調(diào)用方法的情況
由于定義方法時使用的是值,在編譯過程中會對調(diào)用者為指針的類型進行解引用,內(nèi)部實現(xiàn)為 *user.notify()
type user struct {
name string
email string
}
func (u user) notify() {
//將傳入的參數(shù)復制一份,賦值給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)
}
輸出(名子也不會改變):
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)
}
輸出(名子會改變):
Send email to Jack 1139329@163.com
{Jack 1139329@163.com}
4、 使用指針定義方法,使用值調(diào)用方法的情況
內(nèi)部實現(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)
}
輸出(名子會改變):
Send email to Jack 1139329@163.com
{Jack 1139329@163.com}
2、 通過接口傳遞參數(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)
}
//編譯失敗(使用指針接受者來實現(xiàn)一個接口,值類型無法實現(xiàn)對應的接口)
cannot use user (type user) as type notifyInterface in argument to sendNotification:
user does not implement notifyInterface (notify method has pointer receiver)
針對以上情況,《Go語言實戰(zhàn)》一書中這樣講到,首先這是Go語言的一種規(guī)則,具體如下:如果使用指針接受者來實現(xiàn)一個接口,那么只有指向那個類型的指針才能夠實現(xiàn)對應的接口。如果使用值接受者來實現(xiàn)一個接口,那么那個類型的值和指針都能夠實現(xiàn)對應的接口。
為什么會有這樣的限制呢:作者解釋為go編譯器并不總能自動獲得一個值得地址!