浅谈Go语言中的结构体struct & 接口Interface & 反射

2019-11-10 11:16:40于海丽

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

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

栗子一

import "reflect"

func main() {
 var x float64 = 5.21
 fmt.Println("type:", reflect.TypeOf(x)) //type: float64

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

 fmt.Println(v.Interface())     //5.21
 fmt.Printf("value is %1.1en", v.Interface()) //value is 5.2e+00
 y := v.Interface().(float64)
 fmt.Println(y) //5.21
}

栗子二(修改值)

SetXX(x) 因为传递的是 x 的值的副本,所以SetXX不能够改 x,改动 x 必须向函数传递 x 的指针,SetXX(&x) 。

//错误代码!!!
//panic: reflect: reflect.Value.SetFloat using unaddressable value
func main() {
 var a float64
 fv := reflect.ValueOf(&a)
 fv.SetFloat(520.00)
 fmt.Printf("%vn", a)
}
//正确的,传指针
func main() {
 var a2 float64
 fv2 := reflect.ValueOf(&a2)
 fv2.Elem().SetFloat(520.00)
 fmt.Printf("%vn", a2) //520
}

反射操作结构体

reflect.Value.NumField()获取结构体中字段的个数

reflect.Value.Method(n).Call(nil)来调用结构体中的方法

栗子一(通过反射操作结构体)

import "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{"Go", "C", "Python"}

func main() {
 value := reflect.ValueOf(secret)
 fmt.Println(value) //Go & C & Python
 typ := reflect.TypeOf(secret)
 fmt.Println(typ) //main.NotknownType

 knd := value.Kind()
 fmt.Println(knd) // struct

 for i := 0; i < value.NumField(); i++ {
  fmt.Printf("Field %d: %vn", i, value.Field(i))
 }

 results := value.Method(0).Call(nil)
 fmt.Println(results) // [Go & C & Python]
}

栗子二(通过反射修改结构体)

import "reflect"

type T struct {
 A int
 B string
}

func main() {
 t := T{18, "nick"}
 s := reflect.ValueOf(&t).Elem()
 typeOfT := s.Type()

 for i := 0; i < s.NumField(); i++ {
  f := s.Field(i)
  fmt.Printf("%d: %s %s = %vn", i,
   typeOfT.Field(i).Name, f.Type(), f.Interface())
 }

 s.Field(0).SetInt(25)
 s.Field(1).SetString("nicky")
 fmt.Println(t)
}

/*
输出:
0: A int = 18
1: B string = nick
{25 nicky}
*/
import "reflect"

type test struct {
 S1 string
 s2 string
 s3 string
}

var s interface{} = &test{
 S1: "s1",
 s2: "s2",
 s3: "s3",
}

func main() {
 val := reflect.ValueOf(s)
 fmt.Println(val)      //&{s1 s2 s3}
 fmt.Println(val.Elem())    //{s1 s2 s3}
 fmt.Println(val.Elem().Field(0))  //s1
 val.Elem().Field(0).SetString("hehe") //S1大写
}