Go接口、类型断言、反射

接口

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

  • 初始化
type example interface{
        Method1(参数列表) 返回值列表
        Method2(参数列表) 返回值列表
        …
}
package main

import(
	"fmt"
)

// 学生
type Student struct{
	name string
	age int
	sorce int
}

// 老师
type Teacher struct{
	name string
	age int
}

type ClassAction interface{
	Say()
	AfterClass()
}

// 学生继承接口(接口的2个函数 需要全部实例化才行)
func (stu Student)Say()  {
	fmt.Println("my name is",stu.name)
}

func (stu Student)AfterClass()  {
	fmt.Println("Go Home")
}

// 老师继承接口
func (tea Teacher)Say()  {
	fmt.Println("my name is",tea.name)
}

func (tea Teacher)AfterClass()  {
	fmt.Println("Go to Office")
}


func testInterface()  {
	// 定义学生和老师
	var tea Teacher = Teacher{
		name:"波多野结衣",
		age:22,
	}
	var stu	Student = Student{
		name:"程序员",
		age:18,
		sorce:100,
	}

	// 定义一个接口
	var t ClassAction

	// 接口指向学生
	t = stu
	
	// 使用接口里面的函数
	t.Say()
	t.AfterClass()
	 
	// 改变接口指向老师并使用
	t = tea
	t.Say()
	t.AfterClass()
	
	// 打印看看是什么东西
	fmt.Println(t)

}

func main()  {
	testInterface()
}
  • 输出
    my name is 程序员
    Go Home
    my name is 波多野结衣
    Go to Office
    {波多野结衣 22}

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

var f int
var b interface{} 
b = f

// 判断一个变量是否实现了指定接口
v,ok:=b.(ReadFile)

多态

  • 接口通过指向不同的结构体,从而实现多态,例如上面的学生和老师,同时实现Action。

类型断言

  • 类型断言,由于接口是一般类型,不知道具体类型,如果要转成具体类型,需要类型断言

    初始化的两种方式:
    
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,带检查

反射

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

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

    • 获取变量的值:reflect.ValueOf(x).Int()
  • reflect.Value.Kind,获取变量的类别,返回一个常量

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

      type和kind的区别
      大多数情况下会一直,但假如自定义一个结构Student,type是main.Student,而kind是struct
    
package main

import (
	"fmt"
	"reflect"
)

func main() {

	var x float64 = 3.4
	fmt.Println("type:", reflect.TypeOf(x))
	v := reflect.ValueOf(x)
	fmt.Println("value:", v)
	fmt.Println("type:", v.Type())
	fmt.Println("kind:", v.Kind())
	fmt.Println("value:", v.Float())

	fmt.Println(v.Interface())
	fmt.Printf("value is %5.2e\n", v.Interface())
	y := v.Interface().(float64)
	fmt.Println(y)
}
  • 输出
    type: float64
    value: 3.4
    type: float64
    kind: float64
    value: 3.4
    3.4
    value is 3.40e+00
    3.4
  • 通过反射的来改变变量的值
    • reflect.Value.SetXX相关方法,例如:
      reflect.Value.SetInt(),设置整数
func main() {

	var a float64
	fv := reflect.ValueOf(a)
	fv.SetFloat(3.3)
	fmt.Printf("%v\n", a)
}
		上面会修改失败,因为是值类型,如果需要修改,则用fv := reflect.ValueOf(&a)
		即是一个指针,则需要加*来修改,但是反射里面没有*的操作,所以要用 fv.Elem()的操作,即fv.Elem().SetFloat(3.3)

用反射操作结构体

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

反射示范代码1

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\n", i, value.Field(i))
	}
	
	results := value.Method(0).Call(nil)
	fmt.Println(results) // [Ada - Go - Oberon]
}
  • 输出
main.NotknownType
struct
Field 0: Ada
Field 1: Go
Field 2: Oberon
[Ada-Go-Oberon]
发布了32 篇原创文章 · 获赞 16 · 访问量 4703

猜你喜欢

转载自blog.csdn.net/weixin_44879611/article/details/104158150