Learn Go Interface

 

Go的Interface 是一组method(方法)集,只要一个非interface类型数据实现了集合内的方法就能使用该interface

直接看例子,struct继承的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package main

import "fmt"

type Human struct { // 定义一个“Human” struct
	name string
	age int
	phone string
}

type Student struct {
	Human //匿名字段    // 继承Human 的属性
	school string
	loan float32
}

type Employee struct {
	Human //匿名字段   // 继承Human 的属性
	company string
	money float32
}

//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...", lyrics)
}

//Employee重载Human的SayHi方法
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)
	}

// Interface Men被Human,Student和Employee实现
// 因为这三个类型都实现了这两个方法
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()
	}
}

上面的例子使用了struc 继承。只要struct 实现了interface里所有的方法就可以将该struct传给Interface实例。 Go通过interface实现了duck-typing:即”当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。

  • 类似的interface 也可以继承

    例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package main

import (
	"bytes"
	"fmt"
	"io"
)

func main() {
	var wc WriterCloser = NewBufferedWriterCloser()
	wc.Write([]byte("hello youtbube listeners this is a test.."))
	wc.Close()

	r, ok := wc.(io.Reader) // 测试wc是否实现了io.Reader interface内所有的method
	if ok {
		fmt.Println(r)

	} else {
		fmt.Println("Conversion failed")
	}
}

type Writer interface { //定义一个Writer的接口
	Write([]byte) (int, error)
}

type Closer interface { // 定义一个Closer的接口
	Close() error
}
type WriterCloser interface { 
	Writer  // 继承了Writer 接口
	Closer  // 继承了Closer 接口
}

type BufferedWriterCloser struct { // 真正用来实现具体方法的struct, 方法是绑定在这个struct下面的。
	buffer *bytes.Buffer
}

func (bwc *BufferedWriterCloser) Write(data []byte) (int, error) {
	n, err := bwc.buffer.Write(data)
	if err != nil {
		return 0, nil
	}

	v := make([]byte, 8)
	for bwc.buffer.Len() > 8 {
		_, err := bwc.buffer.Read(v)
		if err != nil {
			return 0, nil
		}
		_, err = fmt.Println(string(v))
		if err != nil {
			return 0, err
		}
	}
	return n, nil
}

func (bwc *BufferedWriterCloser) Close() error {
	for bwc.buffer.Len() > 0 {
		data := bwc.buffer.Next(8)
		_, err := fmt.Println(string(data))
		if err != nil {
			return err
		}
	}
	return nil
}

func NewBufferedWriterCloser() *BufferedWriterCloser {
	return &BufferedWriterCloser{
		buffer: bytes.NewBuffer([]byte{}),
	}
}

BufferedWriterCloser 同时实现了Writer, Closer 两个interface 而WriterCloser interface 又继承了Writer, Closer

空Interface 可以用来存储任意类型的数值。

1
2
3
4
5
6
7
// 定义a为空接口
var a interface{}
var i int = 5
s := "Hello world"
// a可以存储任意类型的数值
a = i
a = s

fmt.Println 是如何实现的。

打开fmt的源码文件,你会看到这样一个定义:

1
2
3
type Stringer interface {
	 String() string
}

根据interface 的定义,任何类型的数据只要实现了String() 方法即可被fmt.Println 函数调用。 可以用来定制独特的打印输出。

  • 注:实现了error接口的对象(即实现了Error() string的对象),使用fmt输出时,会调用Error()方法,因此不必再定义String()方法了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main
import (
	"fmt"
	"strconv"
)

type Human struct {
	name string
	age int
	phone string
}

// 通过这个方法 Human 实现了 fmt.Stringer
func (h Human) String() string {
	return "❰"+h.name+" - "+strconv.Itoa(h.age)+" years -  ✆ " +h.phone+"❱"
}

func main() {
	Bob := Human{"Bob", 39, "000-7777-XXX"}
	fmt.Println("This Human is : ", Bob)
}

关于接口传递

当遇到指针接收和值类型接收并存时,必须使用指针传递,goruntime 会自动进行解指针操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
	"fmt"
)

func main() {
	var v WriterCloser = &myWriterCloser{} //遇到下面的调用的方式时,必须使用指针传递,
    /* 否则将会报错《./main.go:8:6: cannot use composite literal (type myWriterCloser) as type WriterCloser in assignment:
        myWriterCloser does not implement WriterCloser (Write method has pointer receiver)》
    */
	fmt.Println(v)

}

type Writer interface {
	Write([]byte) (int, error)
}
type Closer interface {
	Close() error
}

type WriterCloser interface {
	Writer
	Closer
}

type myWriterCloser struct{}

func (m *myWriterCloser) Write(data []byte) (int, error) {// 这里使用了指针传递。
	return 0, nil
}
func (m myWriterCloser) Close() error { 
    //这里使用了值传递。go runtime 会自动进行解指针操作,而使得程序正常运行。
	return nil
}

– 返回顶部 –