Golang中如何实现泛型
Golang中如何实现泛型 你好
我的英语不好,所以这个话题是用翻译器写的。请理解。
我两周前开始学习Go。我主要使用C语言编程。我对使用void指针的泛型模式很感兴趣。我想在Go中实现类似的形式。
我知道Go不支持泛型语法,但可以通过接口实现类似的功能。
这是我正在阅读的书籍中的一个例子:
type fType func(int, int) int
func errorHandler(fn fType) fType {
return func(a int, b int) int {
defer func() {
if err, ok := recover().(error); ok {
log.Printf("run time panic: %v", err)
}
}()
return fn(a, b)
}
}
func divide(a int, b int) int {
return a / b
}
我想将errorHandler的参数改为泛型风格。我知道interface{}的功能与void *类似。以下是我的代码:
type gfType func(...interface{}) interface{}
func gErrorHandler(gfn gfType) gfType {
return func(a ...interface{}) interface{} {
defer func() {
if err, ok := recover().(error); ok {
log.Printf("run time panic: %v", err)
}
}()
return gfn(a...)
}
}
func divide(arg ...interface{}) interface{} {
a := arg[0].(int)
b := arg[1].(int)
return a / b
}
我想知道这是否是Go所倡导的方式。
我也通过接口实现了它,但我不认为这有什么优势。
type runner interface {
run() interface{}
}
func iErrorHandler(r runner) interface{} {
defer func() {
if err, ok := recover().(error); ok {
log.Printf("run time panic: %v", err)
}
}()
return r.run()
}
type div struct {
a, b int
}
func (d div) run() interface{} {
return d.a / d.b
}
感谢你阅读我的话题。
更多关于Golang中如何实现泛型的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
在Go中实现泛型风格,目前主要有两种方式:使用interface{}(Go 1.18之前)和类型参数(Go 1.18+)。你的两种实现都是有效的,但各有特点。
1. 使用interface{}的方式
你的gfType实现确实类似于C的void*,但存在类型安全问题:
func divide(arg ...interface{}) interface{} {
// 需要运行时类型断言,如果类型不匹配会panic
a := arg[0].(int)
b := arg[1].(int)
return a / b
}
// 使用示例
result := gErrorHandler(divide)(10, 2)
fmt.Println(result) // 5
// 但类型不安全:
// result := gErrorHandler(divide)("10", "2") // 运行时会panic
2. 使用接口的方式
你的接口实现更符合Go的惯用法,提供了更好的类型安全:
type Runner interface {
Run() interface{}
}
type ErrorHandler struct{}
func (eh ErrorHandler) Handle(r Runner) interface{} {
defer func() {
if err, ok := recover().(error); ok {
log.Printf("run time panic: %v", err)
}
}()
return r.Run()
}
// 具体实现
type DivRunner struct {
a, b int
}
func (d DivRunner) Run() interface{} {
if d.b == 0 {
panic("division by zero")
}
return d.a / d.b
}
// 使用
handler := ErrorHandler{}
result := handler.Handle(DivRunner{a: 10, b: 2})
3. Go 1.18+ 泛型实现
如果你使用Go 1.18或更高版本,可以使用类型参数实现真正的泛型:
package main
import (
"fmt"
"log"
)
type Operation[T any] func(T, T) T
func ErrorHandler[T any](op Operation[T]) Operation[T] {
return func(a, b T) T {
defer func() {
if err, ok := recover().(error); ok {
log.Printf("run time panic: %v", err)
}
}()
return op(a, b)
}
}
// 整数除法
func DivideInt(a, b int) int {
return a / b
}
// 浮点数除法
func DivideFloat(a, b float64) float64 {
return a / b
}
func main() {
// 类型安全,编译时检查
intDiv := ErrorHandler(DivideInt)
result1 := intDiv(10, 2)
fmt.Println(result1) // 5
floatDiv := ErrorHandler(DivideFloat)
result2 := floatDiv(10.0, 2.0)
fmt.Println(result2) // 5.0
}
4. 更通用的泛型错误处理器
type GenericFunc[In, Out any] func(...In) Out
func GenericErrorHandler[In, Out any](fn GenericFunc[In, Out]) GenericFunc[In, Out] {
return func(args ...In) (result Out) {
defer func() {
if err, ok := recover().(error); ok {
log.Printf("run time panic: %v", err)
// 可以返回零值或处理错误
}
}()
return fn(args...)
}
}
// 使用
func Add(a, b int) int {
return a + b
}
func Concat(a, b string) string {
return a + b
}
func main() {
safeAdd := GenericErrorHandler(Add)
fmt.Println(safeAdd(10, 20)) // 30
safeConcat := GenericErrorHandler(Concat)
fmt.Println(safeConcat("Hello, ", "World!")) // Hello, World!
}
总结
- Go 1.18之前:你的接口实现是推荐的方式,它提供了更好的类型安全和可读性
- Go 1.18+:使用类型参数实现真正的泛型,既有类型安全又有灵活性
interface{}方式虽然灵活,但失去了类型安全,需要谨慎使用
对于错误处理模式,建议结合泛型和接口,根据具体场景选择最合适的实现方式。


