• Go-day06


    今日内容概要:

      1.interface接口

      2.反射

    一、接口

    接口定义

      1.Interface类型可以定义一组方法,当时不需要实现,并且interface不能包含任何变量

      2.接口定义

    type example interface{
    
            Method1(参数列表) 返回值列表
            Method2(参数列表) 返回值列表
            …
    }
    
    /*
    例子:
    */
    type Student interface{
           call() 
           say() string
    }
    

      3.interface类型默认是一个指针

    type example interface{
    
            Method1(参数列表) 返回值列表
            Method2(参数列表) 返回值列表
            …
    }
    
    var a example
    a.Method1()
    
    /*
    没有实现method方法会panic
    */
    

      4.接口的实现

      1. Golang中的接口,不需要显示的实现。只要一个变量,含有接口类型中的所有方法,那么这个变量就实现这个接口。因此,golang中没有implement类似的关键字

      2. 如果一个变量含有了多个interface类型的方法,那么这个变量就实现了多个接口。

      3. 如果一个变量只含有了1个interface的方部分方法,那么这个变量没有实现这个接口。

    package main
    //定义了一个车的接口,满足run,getname,didi就实现了该方法.
    import "fmt"
    
    type Carter interface {
    	Run()
    	GetName() string
    	Didi()
    }
    
    type BMW struct {
    	name string
    }
    
    func (p *BMW) Run(){
    	fmt.Println("this bmw is running")
    }
    
    func(p *BMW) GetName() string{
    	return p.name
    }
    
    func (p *BMW) Didi() {
    	fmt.Println("this bmw is didi")
    }
    
    func main() {
    	var car Carter
    	isBmw := new(BMW)
    	isBmw.name = "liangliang"
    	car = isBmw //将结构体赋值给接口,之后都通过接口调用
    	car.Run()
    	res := car.GetName()
    	fmt.Println(res)
    
    }
    

    多态

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

    接口嵌套

      一个接口可以嵌套在另外的接口上

    package main
    
    import "fmt"
    
    type Writer interface {
    	Write()
    }
    
    type Reader interface {
    	Read()
    }
    
    type WrintReader interface {
    	//此接口类似于继承,只有都实现write和read方法才行
    	Writer
    	Reader
    }
    
    type file struct {
    
    }
    
    func (p *file) Read(){
    	fmt.Println("is read")
    }
    
    func(p *file) Write(){
    	fmt.Println("is write")
    }
    
    func Test(rw WrintReader){
    	rw.Read()
    	rw.Write()
    }
    
    func main() {
    	var f file //声明了一个结构体
    	Test(&f)
    
    
    }
    
    /*
    is read
    is write
    */

    类型断言

      类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型可以采用以下方法进行转换

    //第一种
    var t int
    var x interface{}
    x = t
    y = x.(int)   //转成int
    //第二种
    var t int
    var x interface{}
    x = t
    y, ok = x.(int)   //转成int,带检查

      

    package main
    
    import "fmt"
    
    type Student struct {
    	name string
    	age int
    }
    
    func Test(a interface{}){
    	v,ok := a.(Student) ; if ok{ //接口断言判断
    		//v += 3
    		fmt.Println(v)
    	}else{
    		fmt.Println("convert error")
    	}
    
    	//b := a.(int) //接口断言
    	//b += 3
    	//fmt.Println(b)
    }
    
    func main() {
    	var b Student
    	Test(b)
    }
    
    /*
    { 0}
    */ 

    练习:写一个函数判断传入参数的类型

    package main
    
    import "fmt"
    
    type Student struct {
    	name string
    	age int
    }
    
    func just(a ...interface{}){ //一个interface接口的切片
    	for index,v := range a{
    		switch v.(type) {
    		case int,int32,int64:
    			fmt.Printf("this index is %d,this value is %v,this type is int
    ",index,v)
    		case string:
    			fmt.Printf("this index is %d,this type is %v,this type is string
    ",index,v)
    		case float32,float64:
    			fmt.Printf("this index is %d,this type is %v,this type is float
    ",index,v)
    		case bool:
    			fmt.Printf("this index is %d,this type is %v,this type is bool
    ",index,v)
    
    		case Student:
    			fmt.Printf("this index is %d,this type is %v,this type is student
    ",index,v)
    
    		case *Student:
    			fmt.Printf("this index is %d,this type is %v,this type is *student
    ",index,v)
    		}
    	}
    
    }
    func main() {
    	var stu = Student{name:"ake",age:18}
    	just("hello",9.9,200,true,stu,&stu)
    
    }
    
    
    /*
    this index is 0,this type is hello,this type is string
    this index is 1,this type is 9.9,this type is float
    this index is 2,this value is 200,this type is int
    this index is 3,this type is true,this type is bool
    this index is 4,this type is {ake 18},this type is student
    this index is 5,this type is &{ake 18},this type is *student
    */
    

    类型断言 采用type-switch

    switch t := areaIntf.(type) //areaIntf是结构体
    	{case *Square:        
    		fmt.Printf(“Type Square %T with value %v
    ”, t, t) 
    	case *Circle:       
    		fmt.Printf(“Type Circle %T with value %v
    ”, t, t) 
    	case float32:       
    	fmt.Printf(“Type float32 with value %v
    ”, t)
    	case nil:        
    		fmt.Println(“nil value: nothing to check?”) 
    	default:        
    	fmt.Printf(“Unexpected type %T”, t)
    	}
    

      

    空接口 interface{}

      空接口没有任何方法,所有类型都实现了空接口

    package main
    
    import "fmt"
    
    func main() {
    	var a int
    	var b interface{}
    	b = a
    	fmt.Println(b)
    }
    

      

    判断变量是否实现了指定接口

    package main
    import "fmt"
    
    type Stringer interface {
    	String() string
    }
    
    func main() {
    	var m interface{}
    	if v,ok := m.(Stringer); ok {
    		fmt.Printf("v implements String(): %s
    ", v.String());
    	}
    }
    

    变量slice和接口slice之前的赋值操作. 不能够直接赋值,需要通过for_range赋值

    错误示例:

    var a []int
    var b []interface{}
    b = a
    
    //错误示例

    反射

      1.反射:可以在运行时动态获取变量的相关信息

        import reflect

      2.

        a.reflect.TypeOf,获取变量类型,返回reflect.Type类型

        b.reflect.ValueOf,获取变量值,返回reflect.Value类型

        c.reflect.Value.Kind,获取变量类别,返回一个常量

        d.reflect.Value.Interface(),转换成interface{}类型

      

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

        

    const (
            Invalid Kind = iota
            Bool
            Int
            Int8
            Int16
            Int32
            Int64
            Uint
            Uint8
            Uint16
            Uint32
            Uint64
            Uintptr
            Float32
            Float64
            Complex64
            Complex128
            Array
            Chan
            Func
            Interface
            Map
            Ptr //内存地址
            Slice
            String
            Struct
            UnsafePointer
    ) 
    
    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func main() {
    	var x float64 = 2.3
    	fmt.Println(reflect.TypeOf(x))
    	v := reflect.ValueOf(x)
    	fmt.Println(v)
    	fmt.Println(v.Kind())
    	fmt.Println(v.Type())
    	fmt.Println(v.Float()) //取值
    	//通过反射value,可以转换为接口,可以转换成值类
    	fmt.Println(v.Interface())
    	y := v.Interface().(float64)//通过接口断言
    	fmt.Println(y)
    
    }
    

    4.获取变量的值   

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

    5.通过反射来改变 变量的值  

      reflect.Value.SetXX相关方法,比如:
      reflect.Value.SetFloat(),设置浮点数
      reflect.Value.SetInt(),设置整数
      reflect.Value.SetString(),设置字符串

    容易出问题的case

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    func main() {
    	var x float64 = 2.2
    	//fv := reflect.ValueOf(x) 传入的a为值类型,修改不生效,panic: reflect: reflect.Value.SetFloat using unaddressable value
    	fv := reflect.ValueOf(&x) //传入为内存地址,修改的时候需要Elem()
    	fv.Elem().SetFloat(3.3)
    	fmt.Printf("%v
    ",x)
    
    }
    

     

    反射例子:

    package main
    
    import (
    	"reflect"
    	"fmt"
    )
    
    type Student struct{
        Name  string
        Age   int
        Sex   int
    }
    func(s *Student) Set(name string,age,sex int){
        s.Name = name
        s.Age = age
        s.Sex = sex
    }
    func(s *Student) Getname(name  string){ 
        s.Name = name
    }
     
    func TestStruct_value(){
        var s *Student = &Student{}
        v := reflect.ValueOf(s) //reflect.Value类型
        setinfo := v.MethodByName("Set") //通过reflect反射结构体Set方法
        var par []reflect.Value
        name := "dragon"
        age := 18
        sex := 1
        par = append(par,reflect.ValueOf(name))
        par = append(par,reflect.ValueOf(age))
        par = append(par,reflect.ValueOf(sex))
        setinfo.Call(par)
        fmt.Printf("%v
    ",s)
    }
    
    func main() {
    	TestStruct_value()
    }
    
    /*
    &{dragon 18 1}
    */
    

    用反射操作结构体

      a. reflect.Value.NumField()获取结构体中字段的个数
      b. reflect.Value.Method(n).Call来调用结构体中的方法

      c. reflect.Value.MethodByName(方法名字) 获取结构体方法 可以直接.Call执行该方法

    练习:

     通过反射操作结构体

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type NotknownType struct {
    	s1 string
    	s2 string
    	s3 string
    }
    func (n NotknownType) String() string {
    	return n.s1 + "-" + n.s2 + "-" + n.s3
    }
    var secret interface{} = NotknownType{"Ada", "Go", "Oberon"} //接口可以接收任意类型
    
    func main() {
    	value := reflect.ValueOf(secret) // <main.NotknownType Value>
    	typ := reflect.TypeOf(secret)    // main.NotknownType
    	fmt.Println(typ)
    
    	knd := value.Kind() // struct
    	fmt.Println(knd)
    
    	for i := 0; i < value.NumField(); i++ {
    		fmt.Printf("Field %d: %v
    ", i, value.Field(i))
    		//value.Field(i).SetString("C#")
    	}
    
    	results := value.Method(0).Call(nil)
    	fmt.Println(results) // [Ada - Go - Oberon]
    }
    
    /*
    Ada-Go-Oberon
    main.NotknownType
    struct
    Field 0: Ada
    Field 1: Go
    Field 2: Oberon
    [Ada-Go-Oberon]
    
    */
    

      通过反射修改结构体

    package main
    
    import (
    	"fmt"
    	"reflect"
    )
    
    type T struct {
    	A int
    	B string
    }
    
    func main() {
    	t := T{23, "skidoo"}
    	s := reflect.ValueOf(&t).Elem()
    	typeOfT := s.Type()
    	for i := 0; i < s.NumField(); i++ {
    		f := s.Field(i)
    		fmt.Printf("%d: %s %s = %v
    ", i,
    			typeOfT.Field(i).Name, f.Type(), f.Interface())
    	}
    	s.Field(0).SetInt(77)
    	s.Field(1).SetString("Sunset Strip")
    	fmt.Println("t is now", t)
    }
    
    /*
    0: A int = 23
    1: B string = skidoo
    t is now {77 Sunset Strip}
    */
    

      interface实现一个可以接收任意参数的链表:

    package main
    
    import "fmt"
    
    type LinkNode struct {
    	data interface{}
    	next *LinkNode //定义一个链表节点的结构体
    }
    
    type Link struct { //定义一个链表结构体
    	head *LinkNode
    	tail *LinkNode
    }
    
    
    func (p *Link) InsertChain(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) TailChain(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
    	}
    }
    
    
    
    func main() {
    	var link Link
    	for i:=0 ; i < 10 ; i++ {
    		//link.InsertChain(i)
    		link.TailChain(i)
    	}
    
    	link.Trans()
    
    }
    

      通过interface实现sort排序

    package main
    
    import (
    	"fmt"
    	"math/rand"
    	"sort"
    )
    
    type Student struct {
    	name string
    	age int
    	id int
    }
    
    
    //想使用sort必须实现三种方法,Len,Less,Swap
    type StudentArry []Student
    
    
    
    
    func (p StudentArry) Len() int{
    	return len(p)
    }
    
    func (p StudentArry) Less(i , j int ) bool{
    	return p[i].name < p[j].name
    }
    
    func(p StudentArry) Swap(i,j int){
    	p[i], p[j] = p[j] , p[i]
    }
    
    func main() {
    	var stus StudentArry
    	for i :=0 ; i < 10 ; i++ {
    		stu := Student{
    			name:fmt.Sprintf("stu%d",rand.Intn(100)),
    			age : rand.Intn(100),
    			id : rand.Intn(100),
    		}
    		stus = append(stus,stu)
    	}
    
    	for _,v := range stus{
    		fmt.Println(v.name,v.age,v.id)
    	}
    
    	sort.Sort(stus)
    
    	fmt.Println("--------------")
    
    	for _,v := range stus{
    		fmt.Println(v.name,v.age,v.id)
    	}
    
    }
    
    /*
    stu81 87 47
    stu59 81 18
    stu25 40 56
    stu0 94 11
    stu62 89 28
    stu74 11 45
    stu37 6 95
    stu66 28 58
    stu47 47 87
    stu88 90 15
    --------------
    stu0 94 11
    stu25 40 56
    stu37 6 95
    stu47 47 87
    stu59 81 18
    stu62 89 28
    stu66 28 58
    stu74 11 45
    stu81 87 47
    stu88 90 15
    
    */
    

      

  • 相关阅读:
    Linux
    Linus
    Linux
    Linux
    Linux
    Linux
    Linux
    Linux
    Django日志配置
    linux
  • 原文地址:https://www.cnblogs.com/liujiliang/p/9070762.html
Copyright © 2020-2023  润新知