Golang学习笔记_24——泛型
Golang学习笔记_21——Reader
Golang学习笔记_22——Reader示例
Golang学习笔记_23——error补充
泛型
Go语言从1.18版本开始引入了泛型,这是Go语言的一个重要特性,它允许函数、类型和接口在定义时不必绑定到特定的类型上,而是可以在后续使用时再指定具体的类型。这极大地增强了代码的复用性和灵活性。
1. 泛型中的类型参数
类型参数是泛型函数、泛型类型和泛型接口定义中声明的占位符,它们用于表示在泛型实例化时可以指定的具体类型。
1.1 类型参数声明
在泛型定义中,类型参数通过方括号[]中的类型参数列表进行声明。
func Print[T any](x T) {...}
type Pair[T, U any] struct {...}
type Describer[T any] interface {...}
1.2 类型参数的约束
类型参数可以受到约束,这意味着它们必须满足特定的接口。这通过类型约束来实现。
// Generics type constraints
type Number interface {
int | int64 | float64 // 使用联合类型表示约束
}
func Sum[T Number](nums []T) T {
var sum T
for _, num := range nums {
sum += num
}
return sum
}
测试方法
func TestSum(t *testing.T) {
type args[T Number] struct {
nums []T
}
type testCase[T Number] struct {
name string
args args[T]
want T
}
intTests := []testCase[int]{
{
name: "int add",
args: args[int]{
nums: []int{1, 2, 3},
},
want: 6,
},
}
floatTests := []testCase[float64]{
{
name: "float add",
args: args[float64]{
nums: []float64{1.1, 2.2, 3.3},
},
want: 6.6,
},
}
strTests := []testCase[string]{
{
name: "string add",
args: args[string]{
nums: []string{"1", "2", "3"},
},
want: "123",
},
}
for _, tt := range strTests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.nums); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
for _, tt := range intTests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.nums); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
for _, tt := range floatTests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.nums); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
}
输出结果
strTests 测试结果
# Golang/generics_demo [Golang/generics_demo.test]
./generics_demo_test.go:37:25: string does not satisfy Number (string missing in int | int64 | float64)
./generics_demo_test.go:40:15: string does not satisfy Number (string missing in int | int64 | float64)
./generics_demo_test.go:48:17: string does not satisfy Number (string missing in int | int64 | float64)
intTests floatTests 测试结果
=== RUN TestSum
=== RUN TestSum/int_add
=== RUN TestSum/float_add
--- PASS: TestSum (0.00s)
--- PASS: TestSum/int_add (0.00s)
--- PASS: TestSum/float_add (0.00s)
PASS
1.3 类型参数的实例化
在调用泛型函数、创建泛型类型的实例或赋值给泛型接口时,类型参数会被具体化(实例化)。这可以显式地通过类型参数列表进行,也可以由编译器自动推断。
Print[int](42) // 显式指定T为int类型
Print(3.14) // 编译器自动推断T为float64类型
var p Pair[int, string] // 显式指定T为int,U为string类型
2. 泛型函数
泛型函数允许在函数签名中声明类型参数,这些参数将在函数调用时具体化。
func genericFuncDemo[T any](value T) {
fmt.Println(value)
}
func testGenericFuncDemo() {
genericFuncDemo(1)
genericFuncDemo("hello")
genericFuncDemo(1.1)
}
测试方法
=== RUN Test_testGenericFuncDemo
1
hello
1.1
--- PASS: Test_testGenericFuncDemo (0.00s)
PASS
3. 泛型类型
type Pair[T, U any] struct {
First T
Second U
}
func PairDemo() {
pair := Pair[int, string]{First: 10, Second: "hello"}
fmt.Println(pair.First, pair.Second)
}
测试方法
func TestPairDemo(t *testing.T) {
PairDemo()
}
输出结果
=== RUN TestPairDemo
10 hello
--- PASS: TestPairDemo (0.00s)
PASS
4. 泛型接口
// generics interface
type Describer[T any] interface {
Describe(T) string
}
type IntDescriber struct {
}
func (num IntDescriber) Describe(i int) string {
return fmt.Sprintf("类型是:%d", i)
}
func DescribeDemo() {
var test Describer[int]
test = IntDescriber{}
fmt.Println(test.Describe(100))
}
测试方法
func TestDescribeDemo(t *testing.T) {
DescribeDemo()
}
输出结果
=== RUN TestDescribeDemo
类型是:100
--- PASS: TestDescribeDemo (0.00s)
PASS
源码
// generics_demo.go 文件
package generics_demo
import "fmt"
// Generics type constraints
type Number interface {
int | int64 | float64 // 使用联合类型表示约束
}
func Sum[T Number](nums []T) T {
var sum T
for _, num := range nums {
sum += num
}
return sum
}
func genericFuncDemo[T any](value T) {
fmt.Println(value)
}
func testGenericFuncDemo() {
genericFuncDemo(1)
genericFuncDemo("hello")
genericFuncDemo(1.1)
}
type Pair[T, U any] struct {
First T
Second U
}
func PairDemo() {
pair := Pair[int, string]{First: 10, Second: "hello"}
fmt.Println(pair.First, pair.Second)
}
// generics interface
type Describer[T any] interface {
Describe(T) string
}
type IntDescriber struct {
}
func (num IntDescriber) Describe(i int) string {
return fmt.Sprintf("类型是:%d", i)
}
func DescribeDemo() {
var test Describer[int]
test = IntDescriber{}
fmt.Println(test.Describe(100))
}
// generics_demo_test.go 文件
package generics_demo
import (
"testing"
)
func TestSum(t *testing.T) {
type args[T Number] struct {
nums []T
}
type testCase[T Number] struct {
name string
args args[T]
want T
}
intTests := []testCase[int]{
{
name: "int add",
args: args[int]{
nums: []int{1, 2, 3},
},
want: 6,
},
}
floatTests := []testCase[float64]{
{
name: "float add",
args: args[float64]{
nums: []float64{1.1, 2.2, 3.3},
},
want: 6.6,
},
}
//strTests := []testCase[string]{
//{
//name: "string add",
//args: args[string]{
//nums: []string{"1", "2", "3"},
//},
//want: "123",
//},
//}
//for _, tt := range strTests {
//t.Run(tt.name, func(t *testing.T) {
//if got := Sum(tt.args.nums); got != tt.want {
//t.Errorf("Sum() = %v, want %v", got, tt.want)
//}
//})
//}
for _, tt := range intTests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.nums); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
for _, tt := range floatTests {
t.Run(tt.name, func(t *testing.T) {
if got := Sum(tt.args.nums); got != tt.want {
t.Errorf("Sum() = %v, want %v", got, tt.want)
}
})
}
}
func Test_testGenericFuncDemo(t *testing.T) {
testGenericFuncDemo()
}
func TestPairDemo(t *testing.T) {
PairDemo()
}
func TestDescribeDemo(t *testing.T) {
DescribeDemo()
}
原文地址:https://blog.csdn.net/LuckyLay/article/details/145137075
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!