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

下面是尝试embed类型的源码。


修改函数定义为func (f *F) Modify(f2 F)。谁能解释为什么第一个反射循环中没有显示修改函数?但是在第二个反射循环中,Modify和Validate都可以从 *s 中得到。


package main


import "fmt"

import "reflect"


type F func(int) bool

func (f F) Validate(n int) bool {

    return f(n)

}

func (f *F) Modify(f2 F) {

    *f = f2

}


type B bool

func (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


qq_花开花谢_0
浏览 113回答 2
2回答

拉莫斯之舞

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 的提升方法。

偶然的你

如果m为类型定义了方法T,则该方法对T和都可用*T:type T struct {}func (t T) m() {}func main() {&nbsp; &nbsp;t:=T{}&nbsp; &nbsp;tp:=&T{}&nbsp; &nbsp;t.m()&nbsp; &nbsp;// valid: m defined for T&nbsp; &nbsp;tp.m()&nbsp; // valid: m defined for *T}如果一个方法是用指针接收器定义的,它只被定义为*T而不是为T':func (t *T) n() {}func main() {&nbsp; &nbsp;t:=T{}&nbsp; &nbsp;tp:=&TP{&nbsp; &nbsp;t.n() // Valid: &t is passed to n&nbsp; &nbsp;tp.b&nbsp; // valid&nbsp; &nbsp;mp:=map[int]T{1:t}&nbsp; &nbsp;mp[1].n() // not valid. mp[1] is not addressable&nbsp; &nbsp;pp:=map[int]*T{1:&t}&nbsp; &nbsp;pp[1].n() // valid: pp[1] is *T}这样做的原因很简单:它可以防止无意中修改副本而不是缩进对象。如果带有指针接收器的方法也可用于值类型,则使用以下代码:mp[1].n()n,采用指针接收器,将修改 的值的副本mp[1],而不是存储在 的值mp[1]。具有指针接收器的方法不可用于值类型的事实阻止了这一点,这将成为编译错误,因为n没有为 定义T,并且mp[1]不可寻址,从而阻止了编译器将值转换为指针。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go