当前位置: 首页 > article >正文

Golang学习笔记_24——泛型

Golang学习笔记_21——Reader
Golang学习笔记_22——Reader示例
Golang学习笔记_23——error补充


文章目录

    • 泛型
      • 1. 泛型中的类型参数
        • 1.1 类型参数声明
        • 1.2 类型参数的约束
        • 1.3 类型参数的实例化
      • 2. 泛型函数
      • 3. 泛型类型
      • 4. 泛型接口
    • 源码


泛型

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()
}

http://www.kler.cn/a/504354.html

相关文章:

  • LabVIEW智能水肥一体灌溉控制系统
  • 【HarmonyOS之旅】基于ArkTS开发(二) -> UI开发二
  • git 提交命令记录
  • 深入学习 Python 量化编程
  • mac intel芯片下载安卓模拟器
  • TypeScript Jest 单元测试 搭建
  • 多态(2)
  • 闲谭SpringBoot--ShardingSphere分布式事务探究
  • 使用中间件自动化部署java应用
  • Oracle 学习指南与资料分享
  • React 实战详细讲解:setState 是什么、如何更新及批量处理
  • Java IDEA中Gutter Icons图标的含义
  • 实现一个VSCode插件(从创建到发布)
  • android 内存泄露实战分析
  • 台湾省村里边界2018年4月更新arcgis数据shp格式内容分析测评
  • Unity ShaderGraph中Lit转换成URP的LitShader
  • 【数学】概率论与数理统计(四)
  • docker run一个镜像如何指定最大可使用的内存大小、cpu大小
  • 一.项目课题 <基于TCP的文件传输协议实现>
  • Linux下杂项设备驱动的编写
  • Elasticsearch技术标准解析与实践案例
  • 软路由如何实现电脑手机一机一IP
  • springboot 根据UUID生成唯一的短链接
  • 如何学好数据结构?
  • 大数据原生集群 (Hadoop3.X为核心) 本地测试环境搭建二
  • 如何备考PostgreSQL中级认证