欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang泛型與反射的應(yīng)用詳解

 更新時(shí)間:2022年06月15日 08:35:30   作者:Golang泛型與反射  
如果我想編寫一個(gè)可以輸出任何給定類型的切片并且不使用反射的打印功能,則可以使用新的泛型語(yǔ)法。文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

1. 泛型

1.1 定義

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

1.2 例子

// SumInts 將map的值相加,如果需要添加的數(shù)據(jù)類型不同,那么就需要定義兩個(gè)
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
}

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

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里面所有的內(nèi)置類型,等價(jià)于 interface {}
  • comparable:代表go里面內(nèi)置的可比較類型:int、uint、float、bool、struct、指針等一切可比較類型
  • ~ 符號(hào):用來表示改類型的衍生類型
//類型約束
type Number interface {
	int64 | float64
}
//進(jìn)行類型約束時(shí)就可以使用當(dāng)前類
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結(jié)合使用

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 泛型實(shí)戰(zhàn)

使用泛型定義Json解析方法

//根據(jù)傳入的類型通過反射獲取到類型以及值
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提供了一種機(jī)制,在編譯時(shí)不知道類型的情況下,可更新變量、運(yùn)行時(shí)查看值、調(diào)用方法以及直接對(duì)他們的布局進(jìn)行操作的機(jī)制,稱為反射。

2.2 方法

方法說明返回
reflect.ValueOf()獲取輸入?yún)?shù)接口中的數(shù)據(jù)的值,如果未空則返回 0,注意當(dāng)前方法會(huì)使對(duì)象逃逸到堆空間當(dāng)中返回的是 Value 對(duì)象
reflect.TypeOf()動(dòng)態(tài)獲取輸入?yún)?shù)接口中的值的類型,如果為空則返回 nil返回的是 Type 對(duì)象

Value

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

Type

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

2.3 反射讀取

func stringReflect() {
	name := "這是第一個(gè)反射字符串"
	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: "這是反射結(jié)構(gòu)",
	}
	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("獲取到方法的數(shù)量:%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("根據(jù)Show查找指定方法:%v\n", methodByName)
	//判斷是否實(shí)現(xiàn)了當(dāng)前接口,因?yàn)榻涌陬愋筒荒軇?chuàng)建實(shí)例,所以把 nil 強(qiáng)制轉(zhuǎn)為 *IName 類型
	implements := typeOf.Implements(reflect.TypeOf((*IName)(nil)).Elem())
	fmt.Printf("當(dāng)前類型:%s,是否實(shí)現(xiàn)接口:%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("獲取標(biāo)簽:%v", lookup)
		}
	}
}

2.4 反射操作

func setValue() {
	name := Name{
		Name: "這是反射結(jié)構(gòu)",
	}
	valueOf := reflect.ValueOf(&name)
	fmt.Printf("設(shè)置值之前:%+v\n", valueOf)
	//獲取到地址值
	valueOf = valueOf.Elem()
	name1 := Name{
		Name: "這是通過反射設(shè)置的值",
	}
	valueOf.Set(reflect.ValueOf(name1))
	fmt.Printf("設(shè)置值之后:%+v\n", valueOf)
	//修改字段值
	fieldValueOf := valueOf.FieldByName("Name")
	fieldValueOf.SetString("這是修改字段之后的值")
	fmt.Printf("修改字段之后:%v\n", name.Name)
	//調(diào)用方法
	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("數(shù)組")
	case reflect.Struct:
		fmt.Println("結(jié)構(gòu)體")
	}
    //判斷具體類型
	var ti interface{} = &name
	switch ti.(type) {
	case *Name:
		fmt.Printf("%+v\n", ti)
	}
}

到此這篇關(guān)于Golang泛型與反射的應(yīng)用詳解的文章就介紹到這了,更多相關(guān)Golang泛型與反射內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang?編寫Tcp服務(wù)器的解決方案

    Golang?編寫Tcp服務(wù)器的解決方案

    Golang?作為廣泛用于服務(wù)端和云計(jì)算領(lǐng)域的編程語(yǔ)言,tcp?socket?是其中至關(guān)重要的功能,這篇文章給大家介紹Golang?開發(fā)?Tcp?服務(wù)器及拆包粘包、優(yōu)雅關(guān)閉的解決方案,感興趣的朋友一起看看吧
    2022-10-10
  • 一文帶你了解Go語(yǔ)言中的匿名函數(shù)

    一文帶你了解Go語(yǔ)言中的匿名函數(shù)

    無論是在Go語(yǔ)言還是其他編程語(yǔ)言中,匿名函數(shù)都扮演著重要的角色,本文將詳細(xì)介紹Go語(yǔ)言中匿名函數(shù)的概念和使用方法,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-06-06
  • Golang中數(shù)據(jù)結(jié)構(gòu)Queue的實(shí)現(xiàn)方法詳解

    Golang中數(shù)據(jù)結(jié)構(gòu)Queue的實(shí)現(xiàn)方法詳解

    這篇文章主要給大家介紹了關(guān)于Golang中數(shù)據(jù)結(jié)構(gòu)Queue的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • GoLang基于zap日志庫(kù)的封裝過程詳解

    GoLang基于zap日志庫(kù)的封裝過程詳解

    Zap是我個(gè)人比較喜歡的日志庫(kù),是uber開源的,有較好的性能,在項(xiàng)目開發(fā)中,經(jīng)常需要把程序運(yùn)行過程中各種信息記錄下來,有了詳細(xì)的日志有助于問題排查和功能優(yōu)化,這篇文章主要介紹了GoLang基于zap日志庫(kù)的封裝過程,想要詳細(xì)了解可以參考下文
    2023-05-05
  • Go中的代碼換行問題

    Go中的代碼換行問題

    這篇文章主要介紹了Go中的代碼換行問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • golang json數(shù)組拼接的實(shí)例

    golang json數(shù)組拼接的實(shí)例

    這篇文章主要介紹了golang json數(shù)組拼接的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • go語(yǔ)言搬磚之go jmespath實(shí)現(xiàn)查詢json數(shù)據(jù)

    go語(yǔ)言搬磚之go jmespath實(shí)現(xiàn)查詢json數(shù)據(jù)

    這篇文章主要為大家介紹了go語(yǔ)言搬磚之go jmespath實(shí)現(xiàn)查詢json數(shù)據(jù),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • golang實(shí)現(xiàn)簡(jiǎn)單工廠、方法工廠、抽象工廠三種設(shè)計(jì)模式

    golang實(shí)現(xiàn)簡(jiǎn)單工廠、方法工廠、抽象工廠三種設(shè)計(jì)模式

    這篇文章介紹了golang實(shí)現(xiàn)簡(jiǎn)單工廠、方法工廠、抽象工廠三種設(shè)計(jì)模式的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-04-04
  • 利用rpm打包上線部署golang代碼的方法教程

    利用rpm打包上線部署golang代碼的方法教程

    RPM是RPM Package Manager(RPM軟件包管理器)的縮寫,這篇文章主要給大家介紹了關(guān)于利用rpm打包上線部署golang代碼的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解

    Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解

    這篇文章主要介紹了Go結(jié)合反射將結(jié)構(gòu)體轉(zhuǎn)換成Excel的過程詳解,大概思路是在Go的結(jié)構(gòu)體中每個(gè)屬性打上一個(gè)excel標(biāo)簽,利用反射獲取標(biāo)簽中的內(nèi)容,作為表格的Header,需要的朋友可以參考下
    2022-06-06

最新評(píng)論