日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Golang泛型與反射的應用詳解_Golang

作者:Golang泛型與反射 ? 更新時間: 2022-08-06 編程語言

1. 泛型

1.1 定義

  • 泛型生命周期只在編譯期,旨在為程序員生成代碼,減少重復代碼的編寫
  • 在比較兩個數的大小時,沒有泛型的時候,僅僅只是傳入類型不一樣,我們就要再寫一份一模一樣的函數,如果有了泛型就可以減少這類代碼

1.2 例子

// SumInts 將map的值相加,如果需要添加的數據類型不同,那么就需要定義兩個
func SumInts(m map[string]int64) int64 {
    var s int64
    for _, v := range m {
        s += v
    }
    return s
}
func SumFloats(m map[string]float64) float64 {
    var s float64
    for _, v := range m {
        s += v
    }
    return s
}

如果使用泛型的話只需要定義泛型方法即可(如果報一下編譯錯誤的話,是idea版本過低,升級版本即可,但是運行沒有問題)

func main() {
	ints := make(map[string]int64, 5)
	ints["name"] = 5
	ints["value"] = 6
	floats := make(map[string]float64, 5)
	floats["name"] = 5.6
	floats["value"] = 6.5
	fmt.Printf("Gnneric sums: %v and %v\n", 
		SumIntsOrFloats[string, int64](ints), 
		SumIntsOrFloats[string, float64](floats))
    //可以將類型刪除
    fmt.Printf("Gnneric sums: %v and %v\n", 
		SumIntsOrFloats(ints), 
		SumIntsOrFloats(floats))
}
//SumIntsOrFloats 定義泛型方法
func SumIntsOrFloats[K comparable, V int64 | float64](m map[K]V) V {
	var s V
	for _, v := range m {
        s += v
    }
	return s
}

1.3 自定義泛型類型

  • any:代表 go里面所有的內置類型,等價于 interface {}
  • comparable:代表go里面內置的可比較類型:int、uint、float、bool、struct、指針等一切可比較類型
  • ~ 符號:用來表示改類型的衍生類型
//類型約束
type Number interface {
	int64 | float64
}
//進行類型約束時就可以使用當前類
func SumIntsNumbers[K comparable, V Number](m map[K]V) V {
	var s V
	for _, v := range m {
        s += v
	}
	return s
}

1.4 泛型與switch結合使用

func main() {
	fmt.Println(Get(12))
}
//go中不能直接將泛型與switch使用
func Get[T any](t T) T {
	var ti interface{} = &t
	switch v := ti.(type) {
	case *int:
		*v = 18
	}
	return t
}

1.5 泛型實戰

使用泛型定義Json解析方法

//根據傳入的類型通過反射獲取到類型以及值
func typeFunc[E any](v any, e *E) *E {
	valueOf := reflect.ValueOf(v)
	typeOf := reflect.TypeOf(v)
	if k := typeOf.Kind(); k == reflect.Slice {
		json.Unmarshal(valueOf.Bytes(), e)
	}
	return e
}
func main() {
    user1 := &User{}
	user1 = typeFunc[User](marshal, user1)
	fmt.Printf("%+v", user1)
}

2. 反射

2.1 定義

Golang提供了一種機制,在編譯時不知道類型的情況下,可更新變量、運行時查看值、調用方法以及直接對他們的布局進行操作的機制,稱為反射。

2.2 方法

方法 說明 返回
reflect.ValueOf() 獲取輸入參數接口中的數據的值,如果未空則返回 0,注意當前方法會使對象逃逸到堆空間當中 返回的是 Value 對象
reflect.TypeOf() 動態獲取輸入參數接口中的值的類型,如果為空則返回 nil 返回的是 Type 對象

Value

type Value struct {
	typ *rtype
    //保存類型的值
	ptr unsafe.Pointer
    //指針類型
	flag
    //獲取到值的指向地址,用于通過反射修改值
    Elem() Type
    //給value設置值
    Set()
}

Type

type Type interface {
    //根據索引獲取到方法
	Method(int) Method
    //通過名稱獲取到方法
	MethodByName(string) (Method, bool)
    //獲取到方法的數量
	NumMethod() int
    //獲取結構名稱
	Name() string
    //獲取包路徑
	PkgPath() string
    //獲取到當前類型
	Kind() Kind
    //判斷當前類型是否實現了接口
	Implements(u Type) bool
    //以位為單位返回類型的x
	Bits() int
    //獲取到屬性值的類型,類型必須是:Array、Chan、Map、Pointer、Slice,否則報錯
	Elem() Type
    //獲取到指定所以的值
	Field(i int) StructField
    //獲取到對應索引的嵌套字段
	FieldByIndex(index []int) StructField
	//通過名稱獲取到對應的字段
	FieldByName(name string) (StructField, bool)
	FieldByNameFunc(match func(string) bool) (StructField, bool)
    .....
}

2.3 反射讀取

func stringReflect() {
	name := "這是第一個反射字符串"
	valueOf := reflect.ValueOf(name)
	typeOf := reflect.TypeOf(name)
	fmt.Println(valueOf)
	fmt.Println(typeOf)
}

type Name struct {
	Name string
	Age string `use:"Ok"`
}
func (n Name) Show()  {
	fmt.Println(n.Name)
}
func structReflect() {
	name := Name{
		Name: "這是反射結構",
	}
	valueOf := reflect.ValueOf(name)
	typeOf := reflect.TypeOf(name)
	fmt.Printf("value值:%+v\n", valueOf)
	fmt.Printf("類型名稱:%s\n", typeOf.Name())
	methodNum := typeOf.NumMethod()
	fmt.Printf("獲取到方法的數量:%d", methodNum)
	for i := 0; i < methodNum; i++ {
		method := typeOf.Method(i)
		fmt.Printf("%v\t", method.Name)
	}
	fmt.Println()
	methodByName, _ := typeOf.MethodByName("Show")
	fmt.Printf("根據Show查找指定方法:%v\n", methodByName)
	//判斷是否實現了當前接口,因為接口類型不能創建實例,所以把 nil 強制轉為 *IName 類型
	implements := typeOf.Implements(reflect.TypeOf((*IName)(nil)).Elem())
	fmt.Printf("當前類型:%s,是否實現接口:%s,%v\n", typeOf.Name(), "IName", implements)
	fieldNum := typeOf.NumField()
	for i := 0; i < fieldNum; i++ {
		field := typeOf.Field(i)
		fmt.Printf("字段名稱:%v\t", field.Name)
		if lookup, ok := field.Tag.Lookup("use") ; ok {
			fmt.Printf("獲取標簽:%v", lookup)
		}
	}
}

2.4 反射操作

func setValue() {
	name := Name{
		Name: "這是反射結構",
	}
	valueOf := reflect.ValueOf(&name)
	fmt.Printf("設置值之前:%+v\n", valueOf)
	//獲取到地址值
	valueOf = valueOf.Elem()
	name1 := Name{
		Name: "這是通過反射設置的值",
	}
	valueOf.Set(reflect.ValueOf(name1))
	fmt.Printf("設置值之后:%+v\n", valueOf)
	//修改字段值
	fieldValueOf := valueOf.FieldByName("Name")
	fieldValueOf.SetString("這是修改字段之后的值")
	fmt.Printf("修改字段之后:%v\n", name.Name)
	//調用方法
	methodByName := valueOf.MethodByName("Show")
	values := make([]reflect.Value, 0)
	methodByName.Call(values)
}

2.5 判斷

func judgeType() {
	name := Name{Name: "123"}
	typeOf := reflect.TypeOf(name)
	switch typeOf.Kind() {
	case reflect.Slice:
		fmt.Println("切面")
	case reflect.Array:
		fmt.Println("數組")
	case reflect.Struct:
		fmt.Println("結構體")
	}
    //判斷具體類型
	var ti interface{} = &name
	switch ti.(type) {
	case *Name:
		fmt.Printf("%+v\n", ti)
	}
}

原文鏈接:https://blog.csdn.net/weixin_43915643/article/details/125208010

欄目分類
最近更新