为了账号安全,请及时绑定邮箱和手机立即绑定

Dept的实例的指针被判定为全部三个接口的实现,而Dept的实例只是DeptModeA接口的实现?

Dept的实例的指针被判定为全部三个接口的实现,而Dept的实例只是DeptModeA接口的实现?

Go
千巷猫影 2023-05-02 11:11:55
直接上代码:首先,我定了三个接口、一个结构和三个方法:type DeptModeFull interface {    Name() string     SetName(name string)     Relocate(building string, floor uint8)}type DeptModeA interface {    Name() string     SetName(name string)}type DeptModeB interface {    Relocate(building string, floor uint8)}type Dept struct {     name     string     building string     floor    uint8     Key      string} func (self Dept) Name() string {     return self.name } func (self Dept) SetName(name string) {     self.name = name } func (self *Dept) Relocate(building string, floor uint8) {     self.building = building     self.floor = floor }而后我写了一些测试代码:dept1 :=     Dept{         name:     "MySohu",         building: "Internet",         floor:    7}switch v := interface{}(dept1).(type) {case DeptModeFull:     fmt.Printf("The dept1 is a DeptModeFull.\n")case DeptModeB:     fmt.Printf("The dept1 is a DeptModeB.\n")case DeptModeA:     fmt.Printf("The dept1 is a DeptModeA.\n")default:     fmt.Printf("The type of dept1 is %v\n", v) } deptPtr1 := &dept1if _, ok := interface{}(deptPtr1).(DeptModeFull); ok {     fmt.Printf("The deptPtr1 is a DeptModeFull.\n") }if _, ok := interface{}(deptPtr1).(DeptModeA); ok {     fmt.Printf("The deptPtr1 is a DeptModeA.\n") }if _, ok := interface{}(deptPtr1).(DeptModeB); ok {     fmt.Printf("The deptPtr1 is a DeptModeB.\n") }打印出的内容:The dept1 is a DeptModeA.
 The deptPtr1 is a DeptModeFull. 
The deptPtr1 is a DeptModeA. 
The deptPtr1 is a DeptModeB.哪位大佬给讲一下?
查看完整描述

3 回答

?
蓝山帝景

TA贡献1843条经验 获得超7个赞

假设T是struct,那么Go里面遵循下面几个原则:

  • T的方法集仅拥有 T Receiver 方法。

  • *T 方法集则包含全部方法 (T + *T)。

所以你上面的例子dept1应该是拥有方法:Name和SetName

而&dept1拥有方法:Name、SetName和Relocate

这个就是Go里面在设计方法的时候需要注意Receiver的类型

查看完整回答
反对 回复 2023-05-05
?
RISEBY

TA贡献1856条经验 获得超5个赞

1、结构Dept的方法集中仅包含方法接收者为Dept的方法,即:Name()SetName())。所以,结构Dept的实例仅为DeptModeA的实现。
2、结构的指针*Dept的方法集包含了方法接受者为Dept*Dept的方法,即:Name()SetName()Relocate()。所以,接口Dept的实例的指针为全部三个接口——DeptModeFullDeptModeADeptModeB的实现。 

但是我觉得上述设计和原则与方法调用的设计有些不一致,请看下面的代码:

dept1.Relocate("Media", 12)fmt.Printf("Dept: %v\n", dept1)fmt.Printf("Dept name: %v\n", deptPtr1.Name())

打印的内容:

Dept: {MySohu Media 12 }
Dept name: MySohu

这说明:结构Dept的实例可以调用其指针方法集中的方法。

我觉得设计不一致的地方是:既然结构的访法集不包含接收者为其指针的方法,那又为什么让在结构的实例上可以调用其指针访法集中的方法呢?反过来看,既然结构的实例可以调用其接口访法集上的方法,那为什么不让结构的方法集直接包含这些方法呢?

不过,不管怎样,这引出了第三条规则(官方规范的意译):
3、如果结构的实例x是“可被寻址的”,且&x的方法集中包含方法m,则x.m()(&x).m()的速记(快捷方式)。

查看完整回答
反对 回复 2023-05-05
?
偶然的你

TA贡献1841条经验 获得超3个赞

所以其实

dept1.Relocate("Media", 12)

被自动转化成了?

(&dept1).Relocate("Media", 12)

学习了。

可寻址的意思大概就是已经实例话了。如果你直接

var deptPtr2 *Dept
deptPtr2.Relocate("Media", 12)

就不行。反之:

var deptPtr2 Dept
deptPtr2.Relocate("Media", 12)

就可以。区别就在这里了。

查看完整回答
反对 回复 2023-05-05
  • 3 回答
  • 0 关注
  • 137 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信