Skip to content

Latest commit

 

History

History
853 lines (680 loc) · 13.3 KB

Chapter04Interface.md

File metadata and controls

853 lines (680 loc) · 13.3 KB

Golang Interface

interface类型可以定义一组方法,但是这些方法不需要实现。并且interface不能包含任何变量。

遵循一个interface就是遵循一个规范,令使用方不用关注具体的实现

type example interface{
    Method1(参数列表) 返回值列表
    Method2(参数列表) 返回值列表
}

example: interface implement

package main

import (
	"fmt"
)

type Phone interface {
	send(string) bool
	surf()
}

type Xiaomi struct {
}

// 对interface的实现
func (p Xiaomi) send(data string) bool {
	fmt.Printf("I'm sending %v\n", data)
	return data != ""
}

func (p Xiaomi) surf() {
	fmt.Println("I'm surfing the Internet")
}

func main() {
	var p Phone

	p = Xiaomi{}
	p.surf()
	status := p.send(`"hello"`)
	fmt.Println(status) // true
}

example: 如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出。

package main

import "fmt"

type Student struct {
	Name string
	Age  int
}

func (s Student) String() string {
	return fmt.Sprintf("Name=%v,Age=%v\n", s.Name, s.Age)
}

func main() {
	stu1 := Student{"alpha", 15}
	fmt.Printf("%#v\n", stu1) // main.Student{Name:"alpha", Age:15}
	fmt.Println(stu1)         // Name=alpha,Age=15
}

example: 多态

一种事物的多种形态,都可以按照统一的接口进行操作

package main

import (
	"fmt"
)

type Phone interface {
	call()
}

type NokiaPhone struct {
}

func (nokiaPhone NokiaPhone) call() {
	fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

func (iPhone IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

func main() {
	var phone Phone

	phone = NokiaPhone{}
	phone.call()

	phone = IPhone{}
	phone.call()
}
package main

import (
	"fmt"
)

type Phone interface {
	call()
}

type NokiaPhone struct {
}

func (nokiaPhone *NokiaPhone) call() {
	fmt.Println("I am Nokia, I can call you!")
}

type IPhone struct {
}

func (iPhone *IPhone) call() {
	fmt.Println("I am iPhone, I can call you!")
}

func main() {
	var phone Phone

	phone = &NokiaPhone{}
	phone.call()
	fmt.Printf("%#v\n", phone) //&main.NokiaPhone{}

	phone = &IPhone{}
	phone.call()
	fmt.Printf("%#v\n", phone) //&main.IPhone{}
}

example: interface本质

package main

import (
	"fmt"
)

type Phone interface {
	send(string) bool
	surf()
}

type Xiaomi struct {
}

// 对interface的实现
func (p Xiaomi) send(data string) bool {
	fmt.Printf("I'm sending %v\n", data)
	return data != ""
}

func (p Xiaomi) surf() {
	fmt.Println("I'm surfing the Internet")
}

func main() {
	var p Phone
	// 类型和数值都是<nil>
	fmt.Printf("%#v, %T\n", p, p) // <nil>, <nil>

	p = Xiaomi{}
	fmt.Printf("%#v, %T\n", p, p) //main.Xiaomi{}, main.Xiaomi
}

Attension:

  • Golang中的接口,不需要显式地实现(比如Java中的关键字implement)。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。
  • 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。
  • 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。

example: 一个struct实现多个interface

package main

import (
	"fmt"
)

type Android interface {
	surf()
	playSugar()
}

type Phone interface {
	surf()
	send(string) bool
}

type Xiaomi struct {
}

// 实现了Android和Phone两个接口
func (p Xiaomi) surf() {
	fmt.Println("I'm surfing the Internet")
}

// 两个方法都实现了才算实现了Phone接口
func (p Xiaomi) send(data string) bool {
	fmt.Printf("I'm sending %v\n", data)
	return data != ""
}

// 两个方法都实现了才算实现了Android接口
func (p Xiaomi) playSugar() {
	fmt.Println("I'm playing sugar game")
}

func main() {
	var a Android
	var p Phone
	mi := Xiaomi{}

	a = mi
	p = mi

	a.surf()
	p.surf()
}

interface嵌套

type ReadWrite interface {
	Read(b Buffer) bool
	Write(b Buffer) bool
}
type Lock interface {
	Lock()
	Unlock()
}
type File interface {
	ReadWrite
	Lock
	Close()
}

example: 接口嵌套

package main

import "fmt"

type Reader interface {
	Read()
}

type Writer interface {
	Write()
}

type ReadWriter interface {
	// 接口嵌套
	Reader
	Writer
}

type File struct {
}

func (f *File) Read() {
	fmt.Println("file read")
}

func (f *File) Write() {
	fmt.Println("file write")
}

func Test(rw ReadWriter) {
	rw.Read()
	rw.Write()
}

func main() {
	var f *File
	Test(f)
}

空接口: 空接口没有任何方法,所以所有类型都实现了空接口,也就是任何变量都可以赋值给空接口

package main

import "fmt"

func main() {
	var a interface{}
	fmt.Printf("%v, %T\n", a, a) // <nil>, <nil>
	var b int
	b = 10
	a = b
	fmt.Printf("%v, %T\n", a, a) // 10, int
}

example: interface{}切片

package main

import "fmt"

func main() {
	var a []interface{}
	a = append(a, 10)
	a = append(a, "grey")
	a = append(a, 12.56)
	for _, v := range a {
		fmt.Printf("%v, ", v)
	} // 10, grey, 12.56,
}

example: 普通struct实现Sort接口

Sort interface

// 要实现该Interface这个类型
type Interface interface {
    // Len is the number of elements in the collection.
    // Len 为集合内元素的总数
    Len() int
    // Less reports whether the element with
    // index i should sort before the element with index j.
    //
    // Less 返回索引为 i 的元素是否应排在索引为 j 的元素之前。
    Less(i, j int) bool
    // Swap swaps the elements with indexes i and j.
    // Swap 交换索引为 i 和 j 的元素
    Swap(i, j int)
}
package main

import (
	"fmt"
	"math/rand"
	"sort"
	"time"
)

type Student struct {
	Name string
	Age  int
}

// 通过vscode的codesnippet生成
type StuSlice []Student

func (a StuSlice) Len() int           { return len(a) }
func (a StuSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a StuSlice) Less(i, j int) bool { return a[i].Age < a[j].Age }

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	var students StuSlice
	for i := 0; i < 5; i++ {
		newStu := Student{Name: fmt.Sprintf("stu%d", i), Age: rand.Intn(20)}
		students = append(students, newStu)
	}
	fmt.Println(students)
	sort.Sort(students)
	fmt.Println(students)
}
// [{stu0 6} {stu1 0} {stu2 12} {stu3 12} {stu4 18}]
// [{stu1 0} {stu0 6} {stu2 12} {stu3 12} {stu4 18}]

类型断言: 从普通类型到接口变量直接赋值就行;从接口变量得到传入的类型,就需要类型断言。

example: simple type assertion

package main

import "fmt"

func main() {
	var a interface{}
	var b int

	a = b // 普通类型→interface, 直接赋值
	c := a.(int) // interface→普通类型
	fmt.Printf("%T, %v\n", c, c) //int, 0
}

example: type assertion function

package main

import "fmt"

func Test(i interface{}) {
	res, ok := i.(int)
	if ok {
		fmt.Printf("Result=%v\n", res)
	} else {
		fmt.Println("not int")
	}
}

func main() {
	a := 100
	b := "grey"
	Test(a) // Result=100
	Test(b) // not int
}

example: classifier

package main

import "fmt"

type Student struct{}

func classifier(items ...interface{}) {
	for i, v := range items {
		switch v.(type) {
		case bool:
			fmt.Printf("param #%d is a bool\n", i)
		case float64:
			fmt.Printf("param #%d is a float64\n", i)
		case int:
			fmt.Printf("param #%d is an int\n", i)
		case nil:
			fmt.Printf("param #%d is nil\n", i)
		case string:
			fmt.Printf("param #%d is a string\n", i)
		case *Student:
			fmt.Printf("param #%d is a *Student\n", i)
		default:
			fmt.Printf("param #%d is type is unknown\n", i)
		}
	}
}

func main() {
	a := 10
	b := "grey"
	c := &Student{}
	classifier(a, b, c)
}
// param #0 is an int
// param #1 is a string
// param #2 is a *Student

example: 判断一个变量是否实现了指定接口

package main

import "fmt"

type Person interface {
	Eat()
}

type Student struct{}

func (s Student) Eat() {
	fmt.Println("I'm eating")
}

func main() {
	s := Student{}
	var i interface{} = s
	v, ok := i.(Person)
	fmt.Println(v, ok) // {} true
}

example: 实现一个通用的链表

package main

import "fmt"

type LinkNode struct {
	data interface{}
	next *LinkNode
}

type Link struct {
	head *LinkNode
	tail *LinkNode
}

func (l *Link) LeftAppend(data interface{}) {
	node := &LinkNode{data: data}
	// 空链表判断
	if l.head == nil && l.tail == nil {
		l.head = node
		l.tail = node
	} else {
		node.next = l.head
		l.head = node
	}
}

func (l *Link) RightAppend(data interface{}) {
	node := &LinkNode{data: data}
	// 空链表判断
	if l.head == nil && l.tail == nil {
		l.head = node
		l.tail = node
	} else {
		l.tail.next = node
		l.tail = node
	}
}

func (l *Link) Traverse() {
	head := l.head
	for head != nil {
		fmt.Printf("%v, ", head.data)
		head = head.next
	}
	fmt.Println()
}

func main() {
	var l Link
	for i := 0; i < 3; i++ {
		l.LeftAppend(fmt.Sprintf("boy-%d", i))
	}
	for i := 0; i < 3; i++ {
		l.RightAppend(fmt.Sprintf("girl-%d", i))
	}
	l.Traverse() // boy-2, boy-1, boy-0, girl-0, girl-1, girl-2, 
}

example: init from different files

每个文件中init都会被执行

src/
	project1/
		main
			main.go
		model
			book.go
			student.go
// book.go
package model

import "fmt"

func init() {
	fmt.Println("from book.go")
}

func Book() {
	fmt.Println("book book book")
}
// student.go
package model

import "fmt"

func init() {
	fmt.Println("from student.go")
}

func Student() {
	fmt.Println("student student student")
}
// main.go
package main

import "model"

func main() {
	model.Book()
	model.Student()
}
// from book.go
// from student.go
// student student student
// book book book

example: 负载均衡算法

Balence
Balence

src/
	project1/
		main
			main.go
			customBalence.go
		balence
			instance.go
			balencer.go
			randomBalence.go
			roundrobinBalenc.go
			manager.go
// main.go
package main

import (
	"fmt"
	"math/rand"
	"project1/balence"
	"time"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	// 初始化主机
	var insts []*balence.Instance
	for i := 0; i < 5; i++ {
		host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(255))
		newInst := &balence.Instance{host, "8080"}
		insts = append(insts, newInst)
	}
	// 遍历主机
	for _, v := range insts {
		fmt.Println(v)
	}
	fmt.Println()

	// Manager
	BalenceMethodName := "roundrobin"
	// // from command-line
	// if len(os.Args) > 1 {
	// 	BalenceMethodName = os.Args[1]
	// }

	for {
		inst, err := balence.Balence(BalenceMethodName, insts)
		if err != nil {
			fmt.Println("Do balence err!", err)
			break
		}
		fmt.Println(inst)
		time.Sleep(time.Second)
	}
}
// 192.168.233.22:8080
// 192.168.131.237:8080
// 192.168.51.59:8080
// 192.168.205.157:8080
// 192.168.184.228:8080

// using roundrobin balencer
// 192.168.233.22:8080
// using roundrobin balencer
// 192.168.131.237:8080
// using roundrobin balencer
// 192.168.51.59:8080
// using roundrobin balencer
// 192.168.205.157:8080
// using roundrobin balencer
// 192.168.184.228:8080
// using roundrobin balencer
// 192.168.233.22:8080
// using roundrobin balencer
// 192.168.131.237:8080
// instance.go
package balence

type Instance struct {
	Host string
	Port string
}

func (i *Instance) String() string {
	return i.Host + ":" + i.Port
}
// balencer.go
package balence

type Balencer interface {
	DoBalence([]*Instance) (*Instance, error)
}
// randomBalence.go
package balence

import (
	"errors"
	"math/rand"
)

type RandomBalence struct {
}

func init() {
	RegisterBalence("random", &RandomBalence{})
}

func (r *RandomBalence) DoBalence(insts []*Instance) (inst *Instance, err error) {
	lens := len(insts)
	if lens == 0 {
		err = errors.New("No Instance")
		return
	}
	inst = insts[rand.Intn(lens)]
	return
}
// roundrobinBalence.go
package balence

import "errors"

type RoundrobinBalence struct {
	curIndex int
}

func init() {
	RegisterBalence("roundrobin", &RoundrobinBalence{})
}

func (r *RoundrobinBalence) DoBalence(insts []*Instance) (inst *Instance, err error) {
	lens := len(insts)
	if lens == 0 {
		err = errors.New("No Instance")
		return
	}

	inst = insts[r.curIndex]
	r.curIndex = (r.curIndex + 1) % lens
	return
}
// manager.go
package balence

import "fmt"

type BalenceMgr struct {
	allMethod map[string]Balencer
}

var mgr = BalenceMgr{make(map[string]Balencer)}

func RegisterBalence(name string, b Balencer) {
	mgr.allMethod[name] = b
}

func Balence(name string, insts []*Instance) (inst *Instance, err error) {
	balencer, ok := mgr.allMethod[name]
	if !ok {
		fmt.Errorf("Not such method:%v\n", name)
		return
	}
	fmt.Printf("using %v balencer\n", name)
	inst, err = balencer.DoBalence(insts)
	return
}
// customBalence.go
package main

import (
	"errors"
	"fmt"
	"hash/crc32"
	"math/rand"
	"project1/balence"
)

type HashBalence struct {
}

func init() {
	balence.RegisterBalence("customhash", &HashBalence{})
}

func (h *HashBalence) DoBalence(insts []*balence.Instance) (inst *balence.Instance, err error) {
	lens := len(insts)
	if lens == 0 {
		err = errors.New("No Instance")
		return
	}

	randString := fmt.Sprintf("%v", rand.Int())
	crcTable := crc32.MakeTable(crc32.IEEE)
	hashVal := crc32.Checksum([]byte(randString), crcTable)
	index := int(hashVal) % lens
	inst = insts[index]
	return
}