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

为什么指针类型可以访问嵌入类型的所有方法

为什么指针类型可以访问嵌入类型的所有方法

Go
qq_花开花谢_0 2022-07-11 16:24:42
下面是尝试embed类型的源码。修改函数定义为func (f *F) Modify(f2 F)。谁能解释为什么第一个反射循环中没有显示修改函数?但是在第二个反射循环中,Modify和Validate都可以从 *s 中得到。package mainimport "fmt"import "reflect"type F func(int) boolfunc (f F) Validate(n int) bool {    return f(n)}func (f *F) Modify(f2 F) {    *f = f2}type B boolfunc (b B) IsTrue() bool {    return bool(b)}func (pb *B) Invert() {    *pb = !*pb}type I interface {    Load()    Save()}func PrintTypeMethods(t reflect.Type) {    fmt.Println(t, "has", t.NumMethod(), "methods:")    for i := 0; i < t.NumMethod(); i++ {        fmt.Print(" method#", i, ": ",                t.Method(i).Name, "\n")    }}func main() {    var s struct {        F        *B        I    }    PrintTypeMethods(reflect.TypeOf(s))    fmt.Println()    PrintTypeMethods(reflect.TypeOf(&s))}输出:struct { main.F; *main.B; main.I } has 5 methods: method#0: Invert method#1: IsTrue method#2: Load method#3: Save method#4: Validate*struct { main.F; *main.B; main.I } has 6 methods: method#0: Invert method#1: IsTrue method#2: Load method#3: Modify method#4: Save method#5: Validate
查看完整描述

2 回答

?
拉莫斯之舞

TA贡献1820条经验 获得超10个赞

Method sets

一个类型可能有一个与之关联的方法集。接口类型的方法集就是它的接口。任何其他类型 T 的方法集由所有用接收器类型 T 声明的方法组成。对应指针类型 *T 的方法集是用接收器 *T 或 T 声明的所有方法的集合(即它还包含该方法T 组)。进一步的规则适用于包含嵌入字段的结构,如结构类型部分所述。任何其他类型都有一个空方法集。在方法集中,每个方法必须有一个唯一的非空方法名称。

Struct types

如果 xf 是表示该字段或方法 f 的合法选择器,则称为提升结构 x 中嵌入字段的 字段或方法 f。

...

给定一个结构类型 S 和一个定义类型 T,提升的方法包含在结构的方法集中,如下所示:

  • If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.

  • 如果 S 包含嵌入字段 *T,则 S 和 *S 的方法集都包含带有接收器 T 或 *T 的提升方法。


查看完整回答
反对 回复 2022-07-11
?
偶然的你

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

如果m为类型定义了方法T,则该方法对T和都可用*T:


type T struct {}


func (t T) m() {}


func main() {

   t:=T{}

   tp:=&T{}

   t.m()   // valid: m defined for T

   tp.m()  // valid: m defined for *T

}


如果一个方法是用指针接收器定义的,它只被定义为*T而不是为T':


func (t *T) n() {}


func main() {

   t:=T{}

   tp:=&TP{

   t.n() // Valid: &t is passed to n

   tp.b  // valid


   mp:=map[int]T{1:t}

   mp[1].n() // not valid. mp[1] is not addressable

   pp:=map[int]*T{1:&t}

   pp[1].n() // valid: pp[1] is *T

}

这样做的原因很简单:它可以防止无意中修改副本而不是缩进对象。如果带有指针接收器的方法也可用于值类型,则使用以下代码:


mp[1].n()

n,采用指针接收器,将修改 的值的副本mp[1],而不是存储在 的值mp[1]。具有指针接收器的方法不可用于值类型的事实阻止了这一点,这将成为编译错误,因为n没有为 定义T,并且mp[1]不可寻址,从而阻止了编译器将值转换为指针。


查看完整回答
反对 回复 2022-07-11
  • 2 回答
  • 0 关注
  • 112 浏览
慕课专栏
更多

添加回答

举报

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