go语言的"泛型函数or模板函数"

本文介绍了一种在Golang中实现泛型功能的方法,通过使用interface{}

首先大家知道golang是没有JAVA的泛型函数或者C++的模板函数这种语法的,今天学到了一种很有用的类似泛型操作的语法,拿来和大家分享

以大家喜闻乐见的Add函数来说明,目的是来实现一个泛型的Add函数

先写了三个ADD函数

package main

import (
	"fmt"
)

func Add1(a, b int) int {
	return a + b
}

func Add2(a, b float32) float32 {
	return a + b
}

func Add3(a, b string) string {
	return a + b
}

func main() {
	a1 := Add1(1, 2)
	a2 := Add2(1.33, 6.82)
	a3 := Add3("hello ", "world")
	fmt.Println("a1 =", a1, "a2 =", a2, "a3 =", a3)
}

在把三个ADD函数统一起来前,先学习一个简单的Interface{}的用法,注意int,int32,int64在setvalue的泛型判断中是不同的类型
package main

import (
	"fmt"
)

func SetValue(ret interface{}) {
	switch data := ret.(type) {
	case *float32:
		*data = 3.14
	case *int:
		*data = 23333
	case *int32:
		*data = 32
	case *int64:
		*data = 64
	default:
		fmt.Println("unknow type")
	}
}

func main() {
	var a1 int
	var a2 int32
	var a3 float32
	var a4 int64
	SetValue(&a1)
	SetValue(&a2)
	SetValue(&a3)
	SetValue(&a4)
	fmt.Println("a1 =", a1, "a2 =", a2, "a3 =", a3, "a4 =", a4)
}


相信到这里大部分同学都明白了,我们是要通过switch data:=input.(type)这样的类型判断来实现所谓的泛型,先按照最常规的
伪代码:Add(a,b){return a+b} 来实现
package main

import (
	"fmt"
)

func main() {
	a1 := Add1(1, 2)
	a2 := Add2(1.33, 6.82)
	a3 := Add3("hello ", "world")
	fmt.Println("a1 =", a1, "a2 =", a2, "a3 =", a3)

	b1 := GeneralAdd0(3, 5)
	switch data := b1.(type) {
	case int:
		fmt.Println("b1=", data)
	}
	b2 := GeneralAdd0(1.33, 6.82)
	switch data := b2.(type) {
	case float64:
		fmt.Println("b2=", data)
	}
	b3 := GeneralAdd0("hello ", "add0")
	switch data := b3.(type) {
	case string:
		fmt.Println("b3=", data)
	}
	fmt.Println("b1 =", b1, "b2 =", b2, "b3 =", b3)
}

func Add1(a, b int) int {
	return a + b
}

func Add2(a, b float32) float32 {
	return a + b
}

func Add3(a, b string) string {
	return a + b
}

func GeneralAdd0(a, b interface{}) interface{} {
	switch data := b.(type) {
	case float32:
		switch ta := a.(type) {
		case float32:
			data = data + ta
			return data
		}
	case float64:
		switch ta := a.(type) {
		case float64:
			data = data + ta
			return data
		}
	case int:
		switch ta := a.(type) {
		case int:
			data = data + ta
			return data
		}
	case string:
		switch ta := a.(type) {
		case string:
			data = data + ta
			return data
		}
	default:
		fmt.Println("unknow type")
		return nil
	}

	return nil
}

ps:这里b2其实是个float64类型

也可以传指针
package main

import (
	"fmt"
)

func main() {
	a1 := Add1(1, 2)
	a2 := Add2(1.33, 6.82)
	a3 := Add3("hello ", "world")
	fmt.Println("a1 =", a1, "a2 =", a2, "a3 =", a3)

	b1 := GeneralAdd0(3, 5)
	switch data := b1.(type) {
	case int:
		fmt.Println("b1=", data)
	}
	b2 := GeneralAdd0(1.33, 6.82)
	switch data := b2.(type) {
	case float64:
		fmt.Println("b2=", data)
	}
	b3 := GeneralAdd0("hello ", "add0")
	switch data := b3.(type) {
	case string:
		fmt.Println("b3=", data)
	}
	fmt.Println("b1 =", b1, "b2 =", b2, "b3 =", b3)

	var c1, cret1 int = 10, 42
	GeneralAdd1(&c1, &cret1)
	var c2, cret2 float32 = 5.11, 6.22
	GeneralAdd1(&c2, &cret2)
	var c3, cret3 string = "add1", "I am "
	GeneralAdd1(&c3, &cret3)
	fmt.Println("cret1 =", cret1, "cret2 =", cret2, "cret3 =", cret3)
}

func Add1(a, b int) int {
	return a + b
}

func Add2(a, b float32) float32 {
	return a + b
}

func Add3(a, b string) string {
	return a + b
}

func GeneralAdd0(a, b interface{}) interface{} {
	switch data := b.(type) {
	case float32:
		switch ta := a.(type) {
		case float32:
			data = data + ta
			return data
		}
	case float64:
		switch ta := a.(type) {
		case float64:
			data = data + ta
			return data
		}
	case int:
		switch ta := a.(type) {
		case int:
			data = data + ta
			return data
		}
	case string:
		switch ta := a.(type) {
		case string:
			data = data + ta
			return data
		}
	default:
		fmt.Println("unknow type")
		return nil
	}

	return nil
}

func GeneralAdd1(a, ret interface{}) {
	switch data := ret.(type) {
	case *float32:
		switch ta := a.(type) {
		case *float32:
			*data = *data + *ta
		}
	case *int:
		switch ta := a.(type) {
		case *int:
			*data = *data + *ta
		}
	case *string:
		switch ta := a.(type) {
		case *string:
			*data = *data + *ta
		}
	default:
		fmt.Println("unknow type")
	}
}

看到这里有没有想到一个问题,如果我的add函数是 伪代码:add(a,b,c){return a+b+c},难道我要switch case嵌套3次?这样的代码看着也太难受了
因此自定义的数据类型也是可以判断的哦

package main

import (
	"fmt"
)

func main() {
	a1 := Add1(1, 2)
	a2 := Add2(1.33, 6.82)
	a3 := Add3("hello ", "world")
	fmt.Println("a1 =", a1, "a2 =", a2, "a3 =", a3)

	b1 := GeneralAdd0(3, 5)
	switch data := b1.(type) {
	case int:
		fmt.Println("b1=", data)
	}
	b2 := GeneralAdd0(1.33, 6.82)
	switch data := b2.(type) {
	case float64:
		fmt.Println("b2=", data)
	}
	b3 := GeneralAdd0("hello ", "add0")
	switch data := b3.(type) {
	case string:
		fmt.Println("b3=", data)
	}
	fmt.Println("b1 =", b1, "b2 =", b2, "b3 =", b3)

	var c1, cret1 int = 10, 42
	GeneralAdd1(&c1, &cret1)
	var c2, cret2 float32 = 5.11, 6.22
	GeneralAdd1(&c2, &cret2)
	var c3, cret3 string = "add1", "I am "
	GeneralAdd1(&c3, &cret3)
	fmt.Println("cret1 =", cret1, "cret2 =", cret2, "cret3 =", cret3)

	d1 := IntStruct{a: 9, b: 45, ret: 0}
	GeneralAdd2(&d1)
	d2 := Float32Struct{a: 4.77, b: 7.99, ret: 0.0}
	GeneralAdd2(&d2)
	d3 := StringStruct{a: "I am", b: "stringstruct", ret: ""}
	GeneralAdd2(&d3)
	fmt.Println("d1 =", d1.ret, "d2 =", d2.ret, "d3 =", d3.ret)
}

func Add1(a, b int) int {
	return a + b
}

func Add2(a, b float32) float32 {
	return a + b
}

func Add3(a, b string) string {
	return a + b
}

func GeneralAdd0(a, b interface{}) interface{} {
	switch data := b.(type) {
	case float32:
		switch ta := a.(type) {
		case float32:
			data = data + ta
			return data
		}
	case float64:
		switch ta := a.(type) {
		case float64:
			data = data + ta
			return data
		}
	case int:
		switch ta := a.(type) {
		case int:
			data = data + ta
			return data
		}
	case string:
		switch ta := a.(type) {
		case string:
			data = data + ta
			return data
		}
	default:
		fmt.Println("unknow type")
		return nil
	}

	return nil
}

func GeneralAdd1(a, ret interface{}) {
	switch data := ret.(type) {
	case *float32:
		switch ta := a.(type) {
		case *float32:
			*data = *data + *ta
		}
	case *int:
		switch ta := a.(type) {
		case *int:
			*data = *data + *ta
		}
	case *string:
		switch ta := a.(type) {
		case *string:
			*data = *data + *ta
		}
	default:
		fmt.Println("unknow type")
	}
}

type Float32Struct struct {
	a   float32
	b   float32
	ret float32
}

type IntStruct struct {
	a   int
	b   int
	ret int
}

type StringStruct struct {
	a   string
	b   string
	ret string
}

func GeneralAdd2(ret interface{}) {
	switch data := ret.(type) {
	case *Float32Struct:
		data.ret = data.a + data.b
	case *IntStruct:
		data.ret = data.a + data.b
	case *StringStruct:
		data.ret = data.a + data.b
	default:
		fmt.Println("unknow type")
	}
}
通过自定义IntStruct, Float32Struct, StringStruct这结构体来实现,这样的代码看着就舒服多了

### Go语言中的 #### 的声明方式 自Go 1.18版本起,Go语言正式引入了对的支持。这使得开发者能够编写更加灵活和可重用的代码[^1]。 对于函数而言,在其名称后的方括号内指定类参数列表即可实现化: ```go func Name[T any](param T) { // function body } ``` 这里`T`代表了一个占位符类的标识符,而`any`则表示该类可以接受任何种类的数据输入。当然也可以采用更具体的约束条件来替代`any`关键字。 当涉及到结构体时,则是在定义struct的时候加入类参数部分: ```go type Stack[T any] struct { elements []T } func (s *Stack[T]) Push(v T){ s.elements = append(s.elements, v) } func (s *Stack[T]) Pop()(v T, ok bool){ if len(s.elements)==0{ return nil,false }else{ v=s.elements[len(s.elements)-1] s.elements=s.elements[:len(s.elements)-1] return v,true } } ``` 上述例子展示了如何创建一个名为`Stack`的栈数据结构,并为其提供了基本的操作方法——压入(`Push`)与弹出(`Pop`)元素的功能。 #### 类约束的应用 为了使具有更强的表现力并能更好地适应实际应用场景的需求,可以通过对接口施加一定的限制来进行类约束。具体来说就是在声明时利用接口的形式给出一组特定的方法集合作为限定条件,只有满足这些条件的对象才能被当作合法的类参数传入。 例如下面这段代码就展示了一种基于标准库中`fmt.Stringer`接口所构建出来的字符串转换工具`Stringify`,它只接收实现了`String()`方法的对象数组作为输入参数[^2]: ```go package main import ( "fmt" ) func Stringify[T fmt.Stringer](s []T) (ret []string) { for _, v := range s { ret = append(ret, v.String()) } return ret } type MyString string func (s MyString) String() string { return string(s) } func main() { sl := Stringify([]MyString{"I", "love", "golang"}) fmt.Println(sl) // 输出:[I love golang] } ``` 另外一种常见的做法就是通过组合多个基础类形成复合性的约束规则,如下所示的例子中定义了一个叫做`mixType`的新接口,它可以容纳浮点数或整数值之间的运算操作[^3]: ```go type mixType interface { float32 | int | float64 } func add[T mixType](a, b T) T { c := a + b return c } ``` 这种形式不仅简化了代码书写过程还提高了程序逻辑上的清晰度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值