Go 接口使用

本文来自:CSDN博客golang

感谢做者:fengfengdiandia编程

查看原文:go 接口markdown

Go 语言不是一种 “传统” 的面向对象编程语言:它里面没有继承的概念。数据结构

可是 Go 语言里有很是灵活的接口概念,经过它能够实现不少面向对象的特性。编程语言

接口 定义了一个 方法的集合,可是这些方法 不包含实现代码,它们是 抽象的,接口里也 不能包含变量测试

定义格式

定义接口的通常格式:ui

type Namer interface {
    Method1(param_list) return_type
    Method2(param_list) return_type
   ...
}

上面的 Namer 就是一个接口类型。spa

在 Go 语言中 接口 能够有值, 一个 接口类型 的变量或一个 接口值var ai Namer ,ai 是一个 multiword 数据结构,它的值是 nil。 
它本质上是一个 指针,虽然不彻底是一回事。指向接口值的指针是非法的,会致使代码错误。.net

类型(好比结构体)实现接口方法集中的方法,实现了 Namer 接口类型的变量能够赋值给 ai,此时方法表中的指针会指向被实现的接口方法。3d

实现某个接口的类型,除了实现接口的方法外,还能够有本身的方法。

package main

import "fmt"

type Shaper interface {
    Area() float64
    //  Perimeter() float64
}

type Rectangle struct {
    length float64
    width  float64
}

// 实现 Shaper 接口中的方法
func (r *Rectangle) Area() float64 {
    return r.length * r.width
}

// Set 是属于 Rectangle 本身的方法
func (r *Rectangle) Set(l float64, w float64) {
    r.length = l
    r.width = w
}

func main() {
    rect := new(Rectangle)
    rect.Set(2, 3)
    areaIntf := Shaper(rect)
    fmt.Printf("The rect has area: %f\n", areaIntf.Area())
}

若是去掉 Shaper 中 Perimeter() float64 的注释,编译的时候会遇到下面的错误,这是由于 Rectangle 没有实现 Perimeter() 方法。

cannot convert rect (type *Rectangle) to type Shaper: *Rectangle does not implement Shaper (missing Perimeter method)

多态

一、多个类型能够实现同一个接口。 
二、一个类型能够实现多个接口。

下面咱们增长一个类型 Triangle,一样也为它实现 Shaper 接口。

package main

import "fmt"

type Shaper interface {
    Area() float64
    //  Perimeter() float64
}

// ==== Rectangle ====
type Rectangle struct {
    length float64
    width  float64
}

// 实现 Shaper 接口中的方法
func (r *Rectangle) Area() float64 {
    return r.length * r.width
}

// Set 是属于 Rectangle 本身的方法
func (r *Rectangle) Set(l float64, w float64) {
    r.length = l
    r.width = w
}

// ==== Rectangle End ====

// ==== Triangle ====
type Triangle struct {
    bottom float64
    hight  float64
}

func (t *Triangle) Area() float64 {
    return t.bottom * t.hight / 2
}

func (t *Triangle) Set(b float64, h float64) {
    t.bottom = b
    t.hight = h
}

// ==== Triangle End ====

func main() {
    rect := new(Rectangle)
    rect.Set(2, 3)
    areaIntf := Shaper(rect)
    fmt.Printf("The rect has area: %f\n", areaIntf.Area())

    triangle := new(Triangle)
    triangle.Set(2, 3)
    areaIntf = Shaper(triangle)
    fmt.Printf("The triangle has area: %f\n", areaIntf.Area())
}

  

灵活性

接口的定义是比较灵活的。

假设接口和类型处于不一样的包中,只要类型实现了接口中的所有方法,那么它就实现了此接口。

如今咱们将 Shaper 的定义放在 shaper 包 下, Rectangle 和 Triangle 的定义放在 test 包 下:

[root@ src]# tree
├── test
│   └── test.go
├── main.go
└── shaper
    └── shaper.go
shaper.go
package shaper

type Shaper interface {
    Area() float64
}
test.go
package test

// ==== Rectangle ====
type Rectangle struct {
    length float64
    width  float64
}

// 实现 Shaper 接口的方法
func (r *Rectangle) Area() float64 {
    return r.length * r.width
}

// Set 是属于 Rectangle 本身的方法
func (r *Rectangle) Set(l float64, w float64) {
    r.length = l
    r.width = w
}

// ==== Rectangle End ====

// ==== Triangle ====
type Triangle struct {
    bottom float64
    hight  float64
}

func (t *Triangle) Area() float64 {
    return t.bottom * t.hight / 2
}

func (t *Triangle) Set(b float64, h float64) {
    t.bottom = b
    t.hight = h
}

// ==== Triangle End ====
// main.go
package main

import (
    "fmt"
    "shaper"
    "test"
)

func main() {
    rect := new(test.Rectangle)
    rect.Set(2, 3)
    areaIntf := shaper.Shaper(rect)
    fmt.Printf("The rect has area: %f\n", areaIntf.Area())

    triangle := new(test.Triangle)
    triangle.Set(2, 3)
    areaIntf = shaper.Shaper(triangle)
    fmt.Printf("The triangle has area: %f\n", areaIntf.Area())
}

如今运行 main.go 看看结果吧,嗯嗯,没什么问题,^_^

The rect has area: 6.000000 The triangle has area: 3.000000

 

接口嵌套

一个接口能够包含一个或多个其余的接口,这至关于直接将这些内嵌接口的方法列举在外层接口中同样。

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

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}

type Lock interface {
    Lock()
    Unlock()
}

type File interface {
    ReadWrite
    Lock
    Close()
}

  

类型断言

假如我如今写了一个结构体类型 MyFile 来实现上面的 File 接口,那么我如何知道 MyFile 是否实现了 File 接口呢?

一般咱们使用 类型断言 来测试在某个时刻 varI 是否包含类型 T 的值:

if v, ok : = varI.(T) ; ok { // checked type assertion
    Process(v)
    return
}
// varI is not of type T

  

若是 v 是 varI 转换到类型 T 的值,ok 会是 true;不然 v 是类型 T 的零值,ok 是 false

// main.go
package main

import "fmt"

type MyFile struct{}

func (m *MyFile) Read() bool {
    fmt.Printf("Read()\n")
    return true
}

// ...
// 假设我这里相继实现了 Write(), Lock(),Unlock() 和 Close() 方法

func main() {
    my := new(MyFile)
    fIntf := File(my)

    // 看这里,看这里
    if v, ok := fIntf.(*MyFile); ok {
        v.Read()
    }
}

输出结果是:Read()

要是多个类型实现了同一个接口,好比前面的 areaIntf,要如何测试呢? 
那就要用 type-switch 来判断了。

type-switch 类型判断

switch t := areaIntf.(type) {
case *Rectangle:
    // do something
case *Triangle:
    // do something
default:
    // do something
}
相关文章
相关标签/搜索