Go語言系列(六)- 接口和反射

接口

1. 定義: Interface類型能夠定義一組方法,可是這些不須要實現。而且interface不能包含任何變量。

type example interface{
        Method1(參數列表) 返回值列表
        Method2(參數列表) 返回值列表
}

2.interface類型默認是一個指針

	type example interface{

			Method1(參數列表) 返回值列表
			Method2(參數列表) 返回值列表
			…
	}

	var a example
	a.Method1()

3. 接口實現

  • a. Golang中的接口,不須要顯示的實現。只要一個變量,含有接口類型中的全部方法,那麼這個變量就實現這個接口。所以,golang中沒有implement相似的關鍵字
  • b. 若是一個變量含有了多個interface類型的方法,那麼這個變量就實現了多個接口。
  • c. 若是一個變量只含有了1個interface的方部分方法,那麼這個變量沒有實現這個接口。
package main

import "fmt"

type Car interface {
    GetName() string
    Run()
    DiDi()
}

type Test interface {
    Hello()
}

type BMW struct {
    Name string
}

func (p *BMW) GetName() string {
    return p.Name
}

func (p *BMW) Run() {
    fmt.Printf("%s is running\n", p.Name)
}

func (p *BMW) DiDi() {
    fmt.Printf("%s is didi\n", p.Name)
}
func (p *BMW) Hello() {
    fmt.Printf("%s is hello\n", p.Name)
}

type BYD struct {
    Name string
}

func (p *BYD) GetName() string {
    return p.Name
}

func (p *BYD) Run() {
    fmt.Printf("%s is running\n", p.Name)
}

func (p *BYD) DiDi() {
    fmt.Printf("%s is didi\n", p.Name)
}

func main() {
    var car Car
    var test Test
    fmt.Println(car)

    // var bwm = BMW{}
    // bwm.Name = "寶馬"
    bwm := &BMW{
        Name: "寶馬",
    }
    car = bwm
    car.Run()

    test = bwm
    test.Hello()

    byd := &BMW{
        Name: "比亞迪",
    }
    car = byd
    car.Run()
    // var a interface{}
    // var b int
    // var c float32

    // a = b
    // a = c
    // fmt.Printf("type of a %T\n", a)
}
接口實現案例Car

4.多態:一種事物的多種形態,均可以按照統一的接口進行操做

sort排序node

package main

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

type Student struct {
	Name string
	Id   string
	Age  int
}

type Book struct {
	Name   string
	Author string
}

type StudentArray []Student

func (self StudentArray) Len() int {
	return len(self)
}

func (self StudentArray) Less(i, j int) bool {
	return self[i].Name > self[j].Name
}

func (self StudentArray) Swap(i, j int) {
	self[i], self[j] = self[j], self[i]
}

func main() {
	var stus StudentArray

	for i := 0; i < 10; i++ {
		stu := Student{
			Name: fmt.Sprintf("stu%d", rand.Intn(100)),
			Id:   fmt.Sprintf("110%d", rand.Int()),
			Age:  rand.Intn(100),
		}
		stus = append(stus, stu)
	}

	for _, v := range stus {
		fmt.Println(v)
	}

	fmt.Println()

	sort.Sort(stus)

	for _, v := range stus {
		fmt.Println(v)
	}
}

5. 接口嵌套:一個接口能夠嵌套在另外的接口,以下所示:

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

import "fmt"

type Reader interface {
    Read()
}

type Writer interface {
    Write()
}

type ReadWriter interface {
    Reader
    Writer
}

type File struct {
}

func (self *File) Read() {
    fmt.Println("read data")
}

func (self *File) Write() {
    fmt.Println("write data")
}

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

func main() {
    var f *File
    var b interface{}
    b = f
    // Test(f)

    v, ok := b.(ReadWriter)
    fmt.Println(v, ok)
}
接口嵌套文件讀寫案例

6. 類型斷言,因爲接口是通常類型,不知道具體類型,若是要轉成具體類型,能夠採用如下方法進行轉換:

	var t int
	var x interface{}
	x = t
	y, ok = x.(int)   //轉成int,帶檢查

7. 練習,寫一個函數判斷傳入參數的類型

package main

import (
	"fmt"
)

type Studnet struct {
	Name string
	Sex  string
}

func Test(a interface{}) {
	// b, ok := a.(int)
	b, ok := a.(Studnet)
	if ok == false {
		fmt.Println("convert failed")
		return
	}
	// b += 3
	fmt.Println(b)
}

func just(items ...interface{}) {
	for index, v := range items {
		switch v.(type) {
		case bool:
			fmt.Printf("%d params is bool, value is %v\n", index, v)
		case int, int32, int64:
			fmt.Printf("%d params is int, value is %v\n", index, v)
		case float32, float64:
			fmt.Printf("%d params is float, value is %v\n", index, v)
		case string:
			fmt.Printf("%d params is string, value is %v\n", index, v)
		case Studnet:
			fmt.Printf("%d params is student, value is %v\n", index, v)
		case *Studnet:
			fmt.Printf("%d params is *student, value is %v\n", index, v)
		}
	}
}

func main() {
	var a interface{}
	var b int
	Test(b)
	a = b
	c := a.(int)
	fmt.Printf("%d %T\n", a, a)
	fmt.Printf("%d %T\n", c, c)

	var d Studnet = Studnet{
		Name: "stu1",
		Sex:  "female",
	}
	Test(d)
	just(28, 8.2, "this is a test", d, &d)
}

8. 類型斷言,採用type switch方式

9. 空接口.interface{}

  空接口沒有任何方法,因此全部類型都實現了空接口。python

	var a int
	var b interface{}
	b  = a

10.判斷一個變量是否實現了指定接口

	type Stringer interface {
			String() string 
	}
	var v MyStruct
	if sv, ok := v.(Stringer); ok {
		   fmt.Printf(「v implements String(): %s\n」, sv.String()); 
	} 

11. 實現一個通用的鏈表類

link.gogolang

package main

import (
	"fmt"
)

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

type Link struct {
	head *LinkNode
	tail *LinkNode
}

func (p *Link) InsertHead(data interface{}) {
	node := &LinkNode{
		data: data,
		next: nil,
	}

	if p.tail == nil && p.head == nil {
		p.tail = node
		p.head = node
		return
	}

	node.next = p.head
	p.head = node
}
func (p *Link) InsertTail(data interface{}) {
	node := &LinkNode{
		data: data,
		next: nil,
	}

	if p.tail == nil && p.head == nil {
		p.tail = node
		p.head = node
		return
	}

	p.tail.next = node
	p.tail = node
}

func (p *Link) Trans() {
	q := p.head
	for q != nil {
		fmt.Println(q.data)
		q = q.next
	}
}

main.go算法

package main

func main() {
	var initLink Link
	for i := 0; i < 10; i++ {
		// initLink.InsertHead(i)
		initLink.InsertTail(i)
	}
	initLink.Trans()
}

12. interface{},接口中一個方法也沒有,因此任何類型都實現了空接口,也就是任何變量均可以賦值給空接口。

	var a int
	var b interface{}
	b = a

13.  變量slice和接口slice之間賦值操做,for range  

	var a []int
	var b []interface{}
	b = a

 

14. 實現一個負載均衡調度算法,支持隨機、輪訓等算法

  • balance
package balance

type Balancer interface {
    DoBalance([]*Instance, ...string) (*Instance, error)
}
balance.go
package balance

import "strconv"

type Instance struct {
    host string
    port int
}

func NewInstance(host string, port int) *Instance {
    return &Instance{
        host: host,
        port: port,
    }
}

func (p *Instance) GetHost() string {
    return p.host
}

func (p *Instance) GetPort() int {
    return p.port
}

func (p *Instance) String() string {
    return p.host + ":" + strconv.Itoa(p.port)
}
instance.go
package balance

import "fmt"

type BalanceMgr struct {
    allBalancer map[string]Balancer
}

var mgr = BalanceMgr{
    allBalancer: make(map[string]Balancer),
}

func (p *BalanceMgr) RegisterBalancer(name string, b Balancer) {
    p.allBalancer[name] = b
}

func RegisterBalancer(name string, b Balancer) {
    mgr.RegisterBalancer(name, b)
}

func DoBalance(name string, insts []*Instance) (inst *Instance, err error) {
    balancer, ok := mgr.allBalancer[name]
    if !ok {
        err = fmt.Errorf("Not found %s balancer", name)
        return
    }
    fmt.Printf("use %s balance\n", name)
    inst, err = balancer.DoBalance(insts)
    return
}
mgr.go
package balance

import (
    "errors"
    "math/rand"
)

func init() {
    RegisterBalancer("random", &RandomBalance{})
}

type RandomBalance struct {
}

func (p *RandomBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
    if len(insts) == 0 {
        err = errors.New("No instance")
        return
    }
    lens := len(insts)
    index := rand.Intn(lens)
    inst = insts[index]
    return
}
random.go
package balance

import (
    "errors"
)

func init() {
    RegisterBalancer("roundrobin", &RoundRobinBalance{})
}

type RoundRobinBalance struct {
    curIndex int
}

func (p *RoundRobinBalance) DoBalance(insts []*Instance, key ...string) (inst *Instance, err error) {
    if len(insts) == 0 {
        err = errors.New("No instance")
        return
    }
    lens := len(insts)
    if p.curIndex >= lens {
        p.curIndex = 0
    }
    inst = insts[p.curIndex]
    p.curIndex = (p.curIndex + 1) % lens
    return
}
roundrobin.go
  • main
package main

import (
    "fmt"
    "go_dev/day7/example/example1/balance"
    "hash/crc32"
    "math/rand"
)

type HashBalance struct {
}

func init() {
    balance.RegisterBalancer("hash", &HashBalance{})
}

func (p *HashBalance) DoBalance(insts []*balance.Instance, key ...string) (inst *balance.Instance, err error) {
    var defkey string = fmt.Sprintf("%d", rand.Int())
    if len(key) > 0 {
        // err := fmt.Errorf("hash balance must pass the hash key")
        defkey = key[0]
    }
    lens := len(insts)
    if lens == 0 {
        err = fmt.Errorf("No backend instance")
        return
    }
    crcTable := crc32.MakeTable(crc32.IEEE)
    hashVal := crc32.Checksum([]byte(defkey), crcTable)
    index := int(hashVal) % lens
    inst = insts[index]

    return
}
hash.go
package main

import (
    "fmt"
    "go_dev/day7/example/example1/balance"
    "math/rand"
    "os"
    "time"
)

func main() {
    // 定義一個空切片
    // insts := main([]*balance.Instance)
    var insts []*balance.Instance
    for i := 0; i < 16; i++ {
        host := fmt.Sprintf("192.168.%d.%d", rand.Intn(255), rand.Intn(255))
        one := balance.NewInstance(host, 8080)
        insts = append(insts, one) // 自動對空切片進行擴容
    }
    // 選擇負載均衡算法
    var balanceName = "random"
    if len(os.Args) > 1 {
        balanceName = os.Args[1]
    }
    // var balancer balance.Balancer
    // var conf = "random"
    // if len(os.Args) > 1 {
    //     conf = os.Args[1]
    // }
    // if conf == "random" {
    //     balancer = &balance.RandomBalance{} // 隨機
    //     fmt.Println("use random balancer")
    // } else if conf == "roundrobin" {
    //     balancer = &balance.RoundRobinBalance{} // 輪詢
    //     fmt.Println("use roundrobin balancer")
    // }
    // balancer := &balance.RandomBalance{}  // 隨機
    // balancer := &balance.RoundRobinBalance{} // 輪詢

    for {
        inst, err := balance.DoBalance(balanceName, insts)
        if err != nil {
            // fmt.Println("do balance err:", err)
            fmt.Fprintf(os.Stdout, "do balance error\n")
            continue
        }
        fmt.Println(inst)
        time.Sleep(time.Second)
    }

}

// 運行
// go run go_dev/day7/example/example1/main random
// go run go_dev/day7/example/example1/main roundrobin
// go run go_dev/day7/example/example1/main hash
// 編譯
// go build go_dev/day7/example/example1/main
main.go

反射

1. 反射:能夠在運行時動態獲取變量的相關信息

Import (「reflect」)

兩個函數:json

  • a. reflect.TypeOf,獲取變量的類型,返回reflect.Type類型
  • b. reflect.ValueOf,獲取變量的值,返回reflect.Value類型
  • c. reflect.Value.Kind,獲取變量的類別,返回一個常量
  • d. reflect.Value.Interface(),轉換成interface{}類型

2. reflect.Value.Kind()方法返回的常量

3. 獲取變量的值:

reflect.ValueOf(x).Float() 
reflect.ValueOf(x).Int()
reflect.ValueOf(x).String()
reflect.ValueOf(x).Bool()

4. 經過反射的來改變變量的值

reflect.Value.SetXX相關方法,好比:
reflect.Value.SetFloat(),設置浮點數
reflect.Value.SetInt(),設置整數
reflect.Value.SetString(),設置字符串

5. 用反射操做結構體

a. reflect.Value.NumField()獲取結構體中字段的個數
b. reflect.Value.Method(n).Call來調用結構體中的方法

6.案例

package main

import (
    "fmt"
    "reflect"
)

type Student struct {
    Name  string
    Age   int
    Score float32
}

func test(b interface{}) {
    t := reflect.TypeOf(b)
    fmt.Println(t)
    v := reflect.ValueOf(b)
    k := v.Kind()
    fmt.Println(k)

    iv := v.Interface()
    stu, ok := iv.(Student)
    if ok {
        fmt.Printf("%v %T\n", stu, stu)
    }
}

func testInt(b interface{}) {
    val := reflect.ValueOf(b)
    val.Elem().SetInt(100)

    c := val.Elem().Int()
    fmt.Printf("get value interface{} %d\n", c)
    fmt.Printf("string value: %d\n", val.Elem().Int())
}

func main() {
    var a Student = Student{
        Name:  "stu1",
        Age:   18,
        Score: 92,
    }
    test(a)
    var b int = 1
    testInt(&b)
    fmt.Println(b)
}
反射案例一
package main

import (
    "encoding/json"
    "fmt"
    "reflect"
)

type Student struct {
    Name  string `json:"student_name"`
    Age   int
    Score float32
    Sex   string
}

func (s Student) Print() {
    fmt.Println("---start----")
    fmt.Println(s)
    fmt.Println("---end----")
}

func (s Student) Set(name string, age int, score float32, sex string) {

    s.Name = name
    s.Age = age
    s.Score = score
    s.Sex = sex
}

func TestStruct(a interface{}) {
    tye := reflect.TypeOf(a)
    val := reflect.ValueOf(a)
    kd := val.Kind()
    if kd != reflect.Ptr && val.Elem().Kind() == reflect.Struct {
        fmt.Println("expect struct")
        return
    }

    num := val.Elem().NumField()
    val.Elem().Field(0).SetString("stu1000")
    for i := 0; i < num; i++ {
        fmt.Printf("%d %v\n", i, val.Elem().Field(i).Kind())
    }

    fmt.Printf("struct has %d fields\n", num)

    tag := tye.Elem().Field(0).Tag.Get("json")
    fmt.Printf("tag=%s\n", tag)

    numOfMethod := val.Elem().NumMethod()
    fmt.Printf("struct has %d methods\n", numOfMethod)
    var params []reflect.Value
    val.Elem().Method(0).Call(params)
}

func main() {
    var a Student = Student{
        Name:  "stu01",
        Age:   18,
        Score: 92.8,
    }

    result, _ := json.Marshal(a)
    fmt.Println("json result:", string(result))

    TestStruct(&a)
    fmt.Println(a)
}
反射案例二
相關文章
相關標籤/搜索