欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

struct,interface,method

程序员文章站 2022-07-09 21:26:59
struct类型,值传递的 声明 struct的匿名字段 struct定义的时候是字段名与其类型一一对应,实际上Go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。 ......

struct类型,值传递的

  • 声明

    struct {
      name string
      age int
    }
    
    //几种声明使用方式:
    var p person  // p现在就是person类型的变量了
    p.name = "astaxie"  // 赋值"astaxie"给p的name属性.
    p.age = 25  // 赋值"25"给变量p的age属性
    
    //按照顺序提供初始化值   
    p := person{"tom", 25}
    
    //通过field:value的方式初始化,这样可以任意顺序   
    p := person{age:24, name:"tom"}
    
    //当然也可以通过new函数分配一个指针,此处p的类型为*person  
    p := new(person)

struct的匿名字段

  • struct定义的时候是字段名与其类型一一对应,实际上go支持只提供类型,而不写字段名的方式,也就是匿名字段,也称为嵌入字段。当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。

  • 所有的内置类型和自定义类型都是可以作为匿名字段的

      type human struct {
          age int
          phone string  // human类型拥有的字段
      }
    
      type student struct {
          human  // 匿名字段,struct
          int    // 内置类型作为匿名字段
          phone string  // 学生的phone字段
      }
    
      //student访问属性age的时候,就像访问自己所有用的字段一样
      //匿名字段能够实现字段的继承。
    
    
          // 初始化学生jane
    
      jane := student{human:human{35, "777-444-xxxx"},phone:"666-444-xxxx"}
    
          // 修改匿名内置类型字段
          jane.int = 3
    
          //最外层的优先访问
          //访问student里面的phone字段
          fmt.println(jane.phone)
          // 如果我们要访问human的phone字段
          fmt.println(jane.human.phone)

interface

  • 定义interface

    type interfacename interface {
      func1()
      func2()
      ......
    }
  • interface类型定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了此接口。因此任意的类型都实现了空interface。

  • 如果我们定义了一个interface的变量,那么这个变量里面可以存实现这个interface的任意类型的对象。所以空interface可以存储任意类型的数值。

  • 一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。

  • 嵌入interface如果一个interface1作为interface2的一个嵌入字段,那么interface2隐式的包含了interface1里面的method。

面向对象

method

  • method是附属在一个给定的类型上的,他的语法和函数的声明语法几乎一样,只是在func后面增加了一个receiver(也就是method所依从的主体)。语法如下:

    func (**r receivertype)** funcname(parameters) (results)
  • 虽然method的名字一模一样,但是如果接收者不一样,那么method就不一样
  • receiver可以是值和指针, 两者的差别在于, 指针作为receiver会对实例对象的内容发生操作,而普通类型作为receiver并不对原实例对象发生操作。
  • method能作用在任何你自定义的类型、内置类型、struct等各种类型上面。

指针作为receiver

  • 如果一个method的receiver是*t,你可以在一个t类型的实例变量v上面调用这个method,而不需要&v去调用这个method

  • 如果一个method的receiver是t,你可以在一个t类型的变量p上面调用这个method,而不需要 p去调用这个method

    func (b *box) setcolor(c color) {
      b.color = c
    }
    //*b.color=c和b.color=c这两种方式都是正确的
    //当你用指针去访问相应的字段时(虽然指针没有任何的字段)
    //go知道你要通过指针去获取这个值。
    
    
    func (bl boxlist) paintitblack() {
      for i := range bl {
          bl[i].setcolor(black)
      }
    }
    //paintitblack里面调用setcolor的时候写成
    //(&bl[i]).setcolor(black)和bl[i].setcolor(black)都可以
    //因为setcolor的receiver是*box都可以,因为go知道receiver是指针,他自动帮你转了。

method继承

  • 如果匿名字段实现了一个method,那么包含这个匿名字段的struct也能调用该method。让我们来看下面这个例子

    type human struct {
      name string
      age int
      phone string
    }
    
    type student struct {
      human //匿名字段
      school string
    }
    
    type employee struct {
      human //匿名字段
      company string
    }
    
    
    //在human上面定义了一个method
    func (h *human) sayhi() {a
      fmt.printf("hi, i am %s you can call me on %s\n", h.name, h.phone)
    }
    
    func main() {
      mark := student{human{"mark", 25, "222-222-yyyy"}, "mit"}
      sam := employee{human{"sam", 45, "111-888-xxxx"}, "golang inc"}
      mark.sayhi()
      sam.sayhi()
    }
    

method重写

//如果employee想要实现自己的sayhi
//我们可以在employee上面定义一个method,重写了匿名字段的方法。
func (e *employee) sayhi() {
  fmt.printf("hi, i am %s, i work at %s. call me on %s\n", e.name,e.company, e.phone)
}

参考书籍: