学习go

72 阅读2分钟

Go 语言不是一种  “传统”  的面向对象编程语言:它里面没有类和继承的概念。但是 Go 语言里有非常灵活的 接口 概念,通过它可以实现很多面向对象的特性。

结构体

go
复制代码
type identifier struct {
    field1 type1
    field2 type2
    ...
}

使用 new

结构如下

go
复制代码
var t *T
t = new(T)

举个小例子

go
复制代码
package main
import "fmt"

type struct1 struct {
    i1  int
    f1  float32
    str string
}

func main() {
    ms := new(struct1)
    ms.i1 = 10
    ms.f1 = 15.5
    ms.str= "Chris"

    fmt.Printf("The int is: %d\n", ms.i1)
    fmt.Printf("The float is: %f\n", ms.f1)
    fmt.Printf("The string is: %s\n", ms.str)
    fmt.Println(ms)
}

接口

接口类型是对其它类型行为的抽象和概括;因为接口类型不会和特定的实现细节绑定在一起,通过这种抽象的方式我们可以让我们的函数更加灵活和更具有适应能力

通过如下格式定义接口:

go
复制代码
type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
    ...
}

接口嵌套

比如接口 File 包含了 ReadWrite 和 Lock 的所有方法,它还额外有一个 Close() 方法。

go
复制代码
type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite
    Lock
    Close()
}

面向对象

结构体 vs 接口

结构体的定义如下

go
复制代码
type identifier struct {
    field1 type1
    field2 type2
    ...
}

接口定义如下

go
复制代码
type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
    ...
}

可以看出,结构体是多个变量约束的集合,接口是多个方法约束的集合。两者本质的理念是一样的,主要区别在于作用对象,那么我们将接口粗糙的理解为大号的结构体。


举个例子

go
复制代码
package main

import "fmt"

type Shaper interface {
    Area() float32
}

type Square struct {
    side float32
}

func (sq *Square) Area() float32 {
    return sq.side * sq.side
}

func main() {
    sq1 := new(Square)
    sq1.side = 5

    var areaIntf Shaper
    areaIntf = sq1
    fmt.Printf("The square has area: %f\n", areaIntf.Area())
}

输出:The square has area: 25.000000

由上面的代码中的 areaIntf.Area() 像其他语言中的对象调用方法。而且结构体也支持 new 那么我们可以将结构体大体视为“类”,用面向对象的角度去理解Go语言的设计。但是如同我开头所说的,Go并不是传统的面向对象,这种方式只是提供理解的思路,不能完全套用。

多态

go
复制代码
package main

import "fmt"

type Shaper interface {
    Area() float32
}

type Square struct {
    side float32
}

func (sq *Square) Area() float32 {
    return sq.side * sq.side
}

type Rectangle struct {
    length, width float32
}

func (r Rectangle) Area() float32 {
    return r.length * r.width
}

func main() {

    r := Rectangle{5, 3} // Area() of Rectangle needs a value
    q := &Square{5}      // Area() of Square needs a pointer
    shapes := []Shaper{r, q}
    fmt.Println("Looping through shapes for area ...")
    for n, _ := range shapes {
        fmt.Println("Shape details: ", shapes[n])
        fmt.Println("Area of this shape is: ", shapes[n].Area())
    }
}

输出

go
复制代码
Looping through shapes for area ...
Shape details:  {5 3}
Area of this shape is:  15
Shape details:  &{5}
Area of this shape is:  25

可以看到两个 Area 方法根据不同的结构体调用不同的函数,这就是go的多态。