day16 泛型

染指未来發表於2024-07-03

瞭解泛型

  • 1.18後引入泛型(型別引數)
  • 使用者傳入引數型別
  • 場景使用很少
  • 1.18以前使用 [反射] 來處理不同引數型別的問題
  • 泛型也是使用 [] 和陣列很像! 即:[T any]泛型的約束
  • 泛型的作用:減少程式碼重複型,只針對不同型別相同功能的程式碼
  • 泛型的型別:多個型別(型別不確定)
  • 把靜態語言 轉換成 動態語言

泛型的型別

  • T 就是一個佔位符。 型別的形式引數,T是不確定的,需要在使用時傳遞型別
  • 由於T的型別是不確定的,需要增加一下約束 int|float32|float64|string
package main

import "fmt"

type s1 []int

// Slice 定義泛型切片型別, 型別引數化
/*
	- T 就是一個佔位符。 型別的形式引數,T是不確定的,需要在使用時傳遞型別
	- 由於T的型別是不確定的,需要增加一下約束 int|float32|float64|string
*/
type Slice[T int | float64] []T

func main() {
	/* 泛型的型別 */
	var a s1 = []int{1, 2, 3}
	fmt.Println(a)

	// 使用泛型建立變數。 泛型就是將資料語言有靜態變為動態型別
	var b Slice[int] = []int{1, 2, 3}
	fmt.Printf("%T\n", b) // main.Slice[int]
	var c Slice[float64] = []float64{1.1, 2.2, 3.3}
	fmt.Printf("%T\n", c) // main.Slice[float64]
	fmt.Println("泛型:", b, c)
}

泛型使用

  • 泛型的引數型別的屬性。不止一個,所有東西都可以泛型化
package main

import "fmt"

type MyStruct[T int | string] struct {
	id   T // 多型別
	Name string
	sex  bool
}
type MyInterface[T string | int | float64] interface {
	Print1(data string)
	Print2(data T)
}
type MyChan[T string | int] chan T

func main() {
	/* T 泛型的引數型別的屬性。不止一個,所有東西都可以泛型化 */

	// 1. 泛型化 map  GenericsMap[T,T]
	type GenericsMap[K string | int | float64, V string | int | float64] map[K]V

	// 1.1 例項化泛型 map
	var score1 GenericsMap[string, int] = map[string]int{
		"a": 100,
		"b": 200,
		"c": 300,
	}
	fmt.Printf("score1=%v\n", score1)

	var score2 GenericsMap[int, int] = map[int]int{
		1: 100,
		2: 200,
		3: 300,
	}
	fmt.Printf("score2=%v\n", score2)

	// 2. 泛型化 slice genericsSlice[T]
	type genericsSlice[T string | int | float64 | float32] []T

	// 3. 結構體 泛型 MyStruct
	var genericsStruct1 MyStruct[int] = MyStruct[int]{10, "張三", true}
	fmt.Printf("genericsStruct1=%v\n", genericsStruct1)
	var genericsStruct2 MyStruct[string] = MyStruct[string]{"我不是", "張三", true}
	fmt.Printf("genericsStruct2=%v\n", genericsStruct2)

	// 4. 介面泛型
	//MyInterface()

	// 5. 通道
	//MyChan

}

特殊的泛型

package main

import "fmt"

func main() {
	/* 特殊的泛型:一般不會使用*/

	type MyGenericsInt[T string | int] = int // 結果一定是整型
	var a1 MyGenericsInt[string] = 1
	var b1 MyGenericsInt[int] = 2
	fmt.Println(a1, b1)
	//var c1 MyGenericsInt[string] = "1234" // 因為底層型別設定的是 int。 傳入泛型的型別任意,但是結果必須是int,即:賦值時結果是整型
}

泛型函式

package main

import "fmt"

// MySumSlice 定義泛型型別
type MySumSlice[T string | int | float64 | float32] []T

// MySumSlice 函式呼叫者泛型化
func (s MySumSlice[T]) sum(s1 int) T {
	fmt.Printf("Sum s1: %d\n", s1)
	var sum T
	for _, v := range s {
		sum += v
	}
	return sum
}

// Add 引數泛型化
func Add[T string | int | float64 | float32](a T, b T) T {
	return a + b
}
func main() {
	/*
		泛型函式
			- 1 呼叫者不同,傳入泛型型別。
			- 2.普通函式,即:引數泛型化
	*/

	// 1. 呼叫者不同。 引入泛型化的資料型別呼叫函式
	var intSlice MySumSlice[int] = []int{1, 2, 3, 4, 5}
	intRes := intSlice.sum(1235456)
	fmt.Println("intRes:", intRes)
	var float32Slice MySumSlice[float32] = []float32{1.2, 2.2, 3, 4, 5}
	float32Res := float32Slice.sum(222)
	fmt.Println("float32Res:", float32Res)

	// 2. 函式引數泛型化,同型別引數支援自動推到 ADD(int,int)
	var ia int = 1
	var ib int = 1
	addRes1 := Add[int](ia, ib)
	fmt.Println("addRes1:", addRes1)
	var fa float32 = 12.33
	var fb float32 = 1.235 // 遵循四捨五入
	addRes2 := Add[float32](fa, fb)
	fmt.Println("addRes2:", addRes2)
	var sa string = "abc"
	var sb string = "xyz"
	addRes3 := Add[string](sa, sb)
	fmt.Println("addRes3:", addRes3)

}

自定義泛型

package main

import "fmt"

type genericsInterface interface {
	string | int | float64 | float32 | int8 | int16 | int32
}

func getMax[T genericsInterface](a, b T) T {
	if a > b {
		return a
	}
	return b
}

func main() {
	/* 自定義泛型 */
	var a = 10
	var b = 20
	fmt.Println(getMax(a, b))
	var c = "10"
	var d = "20"
	fmt.Println(getMax(c, d))
}

內建泛型

package main

import "fmt"

// int8 衍生型別
type int8AT int8 // int8AT 就是 int8 的衍生型別
type int8BT int8 // intB 就是 int8 的衍生型別

// MyGenerics01 自定義 泛型型別 介面. ~表示可以匹配該型別的衍生型別
type MyGenerics01 interface {
	~int8
}

func compareTheSize[T MyGenerics01](a, b T) T {
	if a > b {
		return a
	}
	return b
}

func main() {
	/*
		內建泛型
			- any  就是一個泛型,內建型別。interface{}
			- comparable 表示比較所有的型別
			- 新符號 (~)衍生型別
	*/

	// ~ 新符號使用
	var a1 int8AT = 3
	var b1 int8AT = 5
	fmt.Println(a1, b1)
	fmt.Printf("%T\n", a1) // main.int8AT
	fmt.Printf("%T\n", b1) // main.int8BT
	//fmt.Println(compareTheSize(a1, b1))
	fmt.Println(compareTheSize(b1, a1))
}

相關文章