golang面向对象整理

golang知识整理(1)---面向对象

本文用于整理golang和面向对象有关的技术,忽略了一些与其他语言相似的特性,着重关注golang自身特性,主要包括下面几个方面:

  • struct匿名字段
  • method及其特性
  • interface及其特性

struct匿名字段

匿名字段是指struct中只提供类型,不提供变量名的字段,也称为嵌入字段。

当匿名字段是一个struct的时候,那么这个struct所拥有的全部字段都被隐式地引入了当前定义的这个struct。

type Human struct {
    name string
    age int
    weight int
}

type Student struct {
    Human  // 匿名字段,那么默认Student就包含了Human的所有字段
    speciality string
}

当匿名字段内部和外部出现同名字段时,优先访问外层的字段。

例如:

type Human struct {
    name string
    age int
    phone string  // Human类型拥有的字段
}

type Employee struct {
    Human  // 匿名字段Human
    speciality string
    phone string  // 雇员的phone字段
}

当需要调用Employee对象中Human的phone字段时,可以用如下方式访问:

Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
fmt.Println("Bob's work phone is:", Bob.phone)
// 如果我们要访问Human的phone字段
fmt.Println("Bob's personal phone is:", Bob.Human.phone)

method及其特性

golang的方法叫作method,它没有类内部的方法,method的语法如下:

func (r ReceiverType) funcName(parameters) (results)

receiver表示调用该方法的对象类型,可以通过设置不同的receiver类型来实现多态。

method可以设置指针作为receiver的类型,这样才可以改变receiver内部数据的值,如下所示:

func (b *Box) SetColor(c Color) {
    b.color = c
}

另外当receiver为指针时,go可以通过指针直接访问实体的字段,而不需要转成实体,因此函数中*b.Color=c和b.Color=c都是可以的。

如果匿名字段实现了某个method,继承这个匿名字段的类也可以调用这个method,例如:

type Human struct {
    name string
    age int
    phone string
}
type Student struct {
    Human //匿名字段
    school string
}
//在human上面定义了一个method
func (h *Human) SayHi() {
    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"}
    mark.SayHi()
}

继承了匿名字段method的方法也可以重写自己的同名method,如下所示:

type Human struct {
    name string
    age int
    phone string
}

type Employee struct {
    Human //匿名字段
    company string
}

//Human定义method
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

//Employee的method重写Human的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) //Yes you can split into 2 lines here.
}

func main() {
    sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
    sam.SayHi()
}

interface及其特性

interface是一组method的组合,我们通过interface来定义对象的一组行为。实现了interface中所有method的struct就可以说实现了这个interface。如下所示:

type Human struct {
    name string
    age int
    phone string
}
//Human对象实现Sayhi方法
func (h *Human) SayHi() {
    fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
}

// Human对象实现Sing方法
func (h *Human) Sing(lyrics string) {
    fmt.Println("La la, la la la, la la la la la...", lyrics)
}

//Human对象实现Guzzle方法
func (h *Human) Guzzle(beerStein string) {
    fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
}
// 定义interface
type Men interface {
    SayHi()
    Sing(lyrics string)
    Guzzle(beerStein string)
}

Human实现了Men中所有的接口,那么就可以说Human实现了Men。同时被实现的interface也可以存实现这个interface的所有对象,如下所示:

type Men interface {
    SayHi()
    Sing(lyrics string)
}

func main() {
    mike := Student{Human{"Mike", 25, "222-222-XXX"}, "MIT", 0.00}
    paul := Student{Human{"Paul", 26, "111-222-XXX"}, "Harvard", 100}
    sam := Employee{Human{"Sam", 36, "444-222-XXX"}, "Golang Inc.", 1000}
    tom := Employee{Human{"Tom", 37, "222-444-XXX"}, "Things Ltd.", 5000}

    //定义Men类型的变量i
    var i Men

    //i能存储Student
    i = mike
    fmt.Println("This is Mike, a Student:")
    i.SayHi()
    i.Sing("November rain")

    //i也能存储Employee
    i = tom
    fmt.Println("This is tom, an Employee:")
    i.SayHi()
    i.Sing("Born to be wild")

    //定义了slice Men
    fmt.Println("Let's use a slice of Men and see what happens")
    x := make([]Men, 3)
    //这三个都是不同类型的元素,但是他们实现了interface同一个接口
    x[0], x[1], x[2] = paul, sam, mike

    for _, value := range x{
        value.SayHi()
    }
}

Men、Student、Employee三个类均实现了Men接口,因此均可以用Men类型的对象来存储。

另外,空的interface可以存储任意类,这点有点类似c++中的void*类。

根据interface的上述特性,还可以将实现了interface的对象作为参数输入以interface为参数的函数中,以实现函数的变类型参数输入。例如fmt.Println实现变参数输入就是用如下的Stringer接口来实现的,任何实现了这个Stringer接口的对象都可以作为参数被fmt.Println调用。

type Stringer interface {
     String() string
}

Go语言还可以通过断言语法来判断interface所存变量的类型,如下所示:

value, ok := element.(int)

类似于struct的匿名字段,interface也有一种匿名interface可以将一个interface继承至另一个interface,获得其中所有的接口,如下所示:

type Interface interface {
    sort.Interface //嵌入字段sort.Interface
    Push(x interface{}) //a Push method to push elements into the heap
    Pop() interface{} //a Pop elements that pops elements from the heap
}
posted @ 2017-08-07 19:07  程嘉晖  阅读(315)  评论(0编辑  收藏  举报