比如有以下说明:
说明 | 备注 |
---|---|
接口 | 比如一个coder的interface,有code和debug方法 |
方法接收者(实现接口) | 可能有多个,比如phper,golanger,可能是值接收(对象),也可能是指针接收(对象指针) |
调用者为:接口 | 就是接口coder调用 |
调用者为:方法接收者 | 比如phper,golanger,调用者可能是值调用(对象),或者指针调用(对象指针) |
关于调用
调用者为 方法接收者
无论方法接收者(实现接口)是值接收(对象),还是是指针接收(对象指针),都可以用调用者直接调用方法。此时调用者不受是值还是指针的限制。
换句话说:无论接收者是值类型还是指针类型,都可以通过值类型或者指针类型调用。原因是这里有寻址及解引用的隐形操作。
调用者为 接口
先说调用者为接口的意思是:
type Coder interface {
code()
debug()
}
func Work(c Coder){
c.code()
c.debug()
}
type Golang struct {
}
type PHP struct {
}
func (g *Golang) code(){
fmt.Println("golang code")
}
func (g *Golang) debug(){
fmt.Println("golang debug")
}
func (g *PHP) code(){
fmt.Println("php code")
}
func (g PHP) debug(){
fmt.Println("php debug")
}
//这里理解为调用者为接口,
var c Coder=&PHP{}
c.debug()
c.code()
这里主要涉及到接口转换,及需要把coder转为phper或者golanger
结论:实现接收者是值类型的接口方法时,可以正常地用值或指针进行接口转换,(见例2)
但实现接收者是指针类型的方法时,接口转换只能使用指针,不能使用值类型(见例1)。
例1:
package main
import "fmt"
type People interface {
Speak(string) string
}
type Student struct{
Title string
}
func (s *Student) Speak(words string) string {
fmt.Println(s.Title, words)
return s.Title+words
}
func main() {
//如果实现接收者是指针类型,接口转换只能使用指针
s1:=&Student{Title: "HanMei"}
var p People
p=s1
p.Speak("how are you ")
}
例2
package main
import "fmt"
type People interface {
Speak(string) string
}
type Student struct{
Title string
}
func (s Student) Speak(words string) string {
fmt.Println(s.Title, words)
return s.Title+words
}
func main() {
//如果实现接收者是值类型,接口转换可以使用指针,也可以使用值
s1:=&Student{Title: "HanMei:‘"}
s2:=Student{Title: "Li Lei:’"}
var p People
p=s1
p.Speak("how are you ")
p=s2
p.Speak("i am fine ")
}
原因:
通过值可以找到值对应唯一的指针(无论是使用值还是使用指针,方法集都是一样的)。
但是,实现接收者是指针类型的方法时,接口转换只能使用指针,不能使用值类型。这是因为指针方法期望的是一个可以被取地址的对象,而通过值类型进行接口转换时,你可能会传递一个无法取地址的临时对象,这会导致无法调用指针方法。
关于修改
如果方法的接收者是值类型,无论调用者是对象还是对象指针,修改的都是其副本,调用者本身不会更改。
如果方法接收者是指针类型,修改的就是调用者本身。
当你不需要修改状态且要避免并发问题时,值类型接收者是个不错的选择。
当你需要修改状态、需要在并发环境下操作或者需要减少值拷贝时,指针类型接收者更合适。
选择接收者是值类型还是指针类型取决于多种因素,包括可修改性、并发操作和内存开销。
接收者是值类型的场景:
不需要修改接收者的状态:
如果方法不需要修改接收者的状态,而只是基于其属性进行操作,那么可以使用值类型接收者。这样可以避免意外的副作用。
避免并发问题:
值类型接收者是线程安全的,因为它们在方法内部只操作接收者的副本,不会影响原始数据的状态。这在并发环境中往往更容易管理。
接收者是指针类型的情况:
需要修改接收者的状态:
如果方法需要修改接收者的状态,那么你必须使用指针类型接收者。这样可以在方法内部修改原始数据,而不仅仅是操作副本。
避免值拷贝带来的内存开销:
对于大型的结构体或对象,使用指针类型接收者可以避免在方法调用时进行值的拷贝,减少内存和性能开销。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。