1. 程式人生 > >2.15 Go語言反射例項

2.15 Go語言反射例項

需求摘要

  • 所有的商品都有一些共性,例如都有品名、價格,個性則無千無萬;
  • 自行封裝出三種商品(以模擬30萬種商品)
  • 隨意給出一個商品的集合,將每件商品的所有屬性值輸出到《品名.txt》檔案中;

需求分析
該需求的難點在於,給過來的商品是什麼型別都有的,每種不同型別的商品具體有些什麼屬性值我們完全無法預知——所以我們可以通過反射來得到這些屬性的名值;

匯入必要的包

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

胡亂地封裝出一些商品

type Computer struct {
	Name string
	Price float64
	Cpu string
	Memory int
	Disk int
}

type TShirt struct {
	Name string
	Price float64
	Color string
	Size int
	Sex bool
}

type Car struct {
	Name string
	Price float64
	Cap int
	Power string
}

建立商品集合

products := make([]interface{}, 0)
products = append(products, Computer{"未來人類",10000,"英特爾i7",16,1024})
products = append(products, TShirt{"爆款T恤",10000,"紅色",40,false})
products = append(products, Car{"蘭博比基尼",10000,5,"油電混合"})

獲得所有商品的名稱

這裡我們要反射獲得一個叫做Name的屬性

for _,p := range products{
	//先拿到p的值(不在乎型別)
	pValue := reflect.ValueOf(p)

	//再通過p值,拿到p下面的名為Name的屬性值
	nameValue := pValue.FieldByName("Name")

	//Name屬性的值,反射形式化為正射形式(interface{}型別)
	nameInterface := nameValue.Interface()

	//將空介面斷言為string
	name := nameInterface.(string)
	fmt.Println(name)

	WriteObj2File(p,"D:/BJBlockChain180x/demos/W2/day4/file/"+name+".txt")
}

上述程式碼還可以簡寫為

for _,p := range products{
	name := reflect.ValueOf(p).FieldByName("Name").Interface().(string)
	fmt.Println(name)
	WriteObj2File(p,"D:/BJBlockChain180x/demos/W2/day4/file/"+name+".txt")
}

輸出商品資訊到指定檔案
這裡我們通過反射獲得了任意物件的所有屬性名值

func WriteObj2File(obj interface{},filename string) error {

	//開啟檔案
	file, err := os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil{
		return err
	}
	defer file.Close()

	//獲得例項資訊
	oType := reflect.TypeOf(obj)
	oValue := reflect.ValueOf(obj)

	//獲取obj的所有屬性名值
	for i:=0;i<oType.NumField();i++{

		//屬性名
		fName := oType.Field(i).Name

		//獲得屬性值的字串形式
		fValue := oValue.FieldByName(fName).Interface()
		fValueStr := fmt.Sprint(fValue)

		//寫入檔案
		_, err = file.WriteString(fName + ":" + fValueStr + "\n")
		if err != nil{
			return err
		}
	}

	return nil
}

總結

使用常規“正射”對未知型別進行操作難於登天,有了反射,EASY JOB!