• Go方法集


    参考:

    https://blog.csdn.net/weixin_38138153/article/details/119254927

    https://blog.csdn.net/qihoo_tech/article/details/104707905

    一、规则

    Golang方法集规则:

    类型 方法参数接收类型
    T (t T)
    *T (t Y) and (t *T)

    说明:即T类型,只能调用 接收类型是T的方法; *T类型,能调用 接收类型是T或者*T的方法;

    ★★★上述表格换种形式,如下(比较好理解):

    方法参数接收类型 类型
    (t T) T and *T
    (t *T) *T

    说明:即接收类型是T类型,那么T或者*T的变量可以调用该方法;接收类型是*T的类型,那么只能*T的变量可以调用该方法;

    方法集总结(看完所有,再来体会下面5个规则):

    • 类型 T 方法集包含全部 receiver T 方法。
    • 类型 *T 方法集包含全部 receiver T + *T 方法。
    • 如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。
    • 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法。
    • 不管嵌入 T 或 *T,*S 方法集总是包含 T + *T 方法。

    二、普通类型的方法集

    当类型调用自己申明的方法的时候,不需要考虑方法集,因为有语法糖帮忙;

    package main
    
    import "fmt"
    
    type user struct {
        name string
        age  int
    }
    
    // 指针类型
    func (usr *user) sayHello() {
        fmt.Printf("user %s age is %d say hello\n", usr.name, usr.age)
    }
    
    // 结构体类型
    func (usr user) sayHi() {
        fmt.Printf("user %s age is %d say hi\n", usr.name, usr.age)
    }
    
    func main() {
        u1 := user{name: "dog", age: 2}
        u1.sayHello()  // 按照golang方法集规则,此处应该报错;原因是编译器在编译的时候为我们加上了取地址操作,为go语法糖
        u1.sayHi()
    
        u2 := &user{name: "cat", age: 4}
        u2.sayHello()
        u2.sayHi()
    }

    普通类型的嵌入方法:

    package main
    
    import (
        "fmt"
    )
    
    type Person struct {
        name string
        age  int
    }
    
    func (s Person) GetName() {
        fmt.Printf("this is %s\n", s.name)
    }
    
    func (s *Person) SetName(newName string)  {
        s.name = newName
    }
    
    type Worker1 struct {
        Person
    }
    
    type Worker2 struct {
        *Person
    }
    
    func main() {
        s1 := Worker1{}
        s1.SetName("worker01")
        s1.GetName()
    
        s2 := &Worker1{}
        s2.SetName("worker2")
        s2.GetName()
    
        s3 := &Worker2{}
        s3.SetName("worker3")  // 因为Person类型值为nil; runtime error: invalid memory address or nil pointer dereference
        s3.GetName()
    
        s4 := &Worker2{&Person{name: "work4", age: 20}}
        s4.SetName("worker04")
        s4.GetName()
    }

    三、接口的方法集

    普通接口方法,规则如下:

    • 类型 T 方法集包含全部 receiver T 方法。
    • 类型 *T 方法集包含全部 receiver T + *T 方法。

    package main
    
    import "fmt"
    
    type personer interface {
        talk()
        eat()
    }
    
    type user struct {
        name string
        age  int
    }
    
    func (usr user) talk() {
        fmt.Printf("user %s age is %d, talk\n", usr.name, usr.age)
    }
    
    func (usr *user) eat() {
        fmt.Printf("user %s age is %d, wat\n", usr.name, usr.age)
    }
    
    func main() {
        var x personer
        u := user{name: "dog", age: 2}
        
        x = &u
        x.talk()
        x.eat()
    
        x = u  // 此处会报错;cannot use u (type user) as type personer in assignment: user does not implement personer (eat method has pointer receiver)
        x.talk()
        x.eat()
    }

    说明:代码中为什么只有 *user 类型实现了person接口?首先,eat方法是用 *user作为参数的,这个当然算实现了eat方法,然后,talk方法是用 user作为参数的。根据上面的表格规则,当参数类型是T时,传T或者 *T 都是可以接受的,所以 *user 也实现了eat方法。反观user类型,eat方法中指定是 *user 类型,根据上面的表格,当参数是 *T 时,只能传 *T 所以user类型没有能访问到eat方法,所以它没有实现person接口。

    嵌入接口方法,规则如下:

    规则1: • 如类型 S 包含匿名字段 T,则 S 和 *S 方法集包含 T 方法。
    规则2: • 如类型 S 包含匿名字段 *T,则 S 和 *S 方法集包含 T + *T 方法。
    规则3: • 不管嵌入 T 或 *T,*S 方法集总是包含 T + *T 方法。

    package main
    
    import (
        "fmt"
    )
    
    type Humaner interface {
        GetName()
        SetName(string)
    }
    
    type Person struct {
        name string
        age  int
    }
    
    func (s Person) GetName() {
        fmt.Printf("this is %s\n", s.name)
    }
    
    func (s *Person) SetName(newName string)  {
        s.name = newName
    }
    
    type Worker1 struct {
        Person
    }
    
    type Worker2 struct {
        *Person
    }
    
    func main() {
        // 根据规则三,不满足SetName方法,所以没有实现接口
        var x1 Humaner = Worker1{}  //此处报错;cannot use Worker1{} (type Worker1) as type Humaner in assignment: Worker1 does not implement Humaner (SetName method has pointer receiver)
        x1.SetName("worker01")
        x1.GetName()
    
        var x2 Humaner = &Worker1{} // ok,满足规则1、3
        x2.SetName("worker02")
        x2.GetName()
    
        var x3 Humaner = Worker2{&Person{}} // ok,满足规则2
        x3.SetName("worker03")
        x3.GetName()
    
        var x4 Humaner = &Worker2{&Person{}} // ok,满足规则2
        x4.SetName("worker04")
        x4.GetName()
    }

    .

  • 相关阅读:
    Rust语言学习笔记(11)
    Rust语言学习笔记(10)
    Rust语言学习笔记(9)
    Rust语言学习笔记(8)
    趣味编程:静夜思(Rust版)
    Python sorted()
    Python 魔法方法
    Python filter()
    Python的map和reduce
    Python函数的参数
  • 原文地址:https://www.cnblogs.com/wsongl/p/15748977.html
Copyright © 2020-2023  润新知