Golang中泛型类型的探讨
Golang中泛型类型的探讨 大家好
我正在尝试使用新的泛型方法编写一个用于Option类型的库,我认为这是使用泛型的一个有效场景。
我希望能够在模型中使用这些数据类型,因此需要实现Scan和Value方法。以下是我为结构体编写的代码:
type Option[T any] struct {
value T
isSome bool
}
这是我为Scan方法设计的实现。目前只实现了int64,但当然我希望支持更多的数据类型。
func (o *Option[T]) Scan(value any) error {
if reflect.TypeOf(value) == nil {
*o = Option[T]{}
return nil
}
switch reflect.TypeOf(value) {
case reflect.TypeOf(int64(0)):
var i sql.NullInt64
if err := i.Scan(value); err != nil {
return err
}
if i.Valid {
*o = Option[int64]{
value: int64(i.Int64),
isSome: true,
}
} else {
*o = Option[T]{}
}
}
return nil
}
这段代码无法编译,因为我无法将Option[int64]赋值给o,这我能理解。但是,我该如何编写这样的泛型函数呢?
更多关于Golang中泛型类型的探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
4 回复
是的,这里有一个示例
sentTime := Option[time.Time]{
}
db.QueryRow("SELECT sent_time from mail_sender").Scan(&sentTime)
if (sentTime.IsNone(){
//Send mail
}
你好 @Michael_Hugi,
泛型函数背后的理念是,它能够对参数执行统一的操作,而无需知道具体的类型。如果函数体需要深入探究参数的实际类型,那么这个函数就不能再被认为是泛型的了。因此,我认为类型参数无法帮助你实现你想要的功能。在运行时处理未知类型通常是空接口和反射的领域。
(但如果能证明我是错的,我会很高兴。我对泛型的了解还不够深入,并且确信还有一些泛型结构有待发现。)
这是一个典型的泛型类型约束问题。你需要为泛型类型添加类型约束,确保类型 T 能够支持你需要的操作。以下是修改后的实现:
import (
"database/sql"
"database/sql/driver"
"reflect"
)
// 定义支持的类型约束
type Scannable interface {
~int | ~int64 | ~string | ~bool | ~float64
}
type Option[T Scannable] struct {
value T
isSome bool
}
func (o *Option[T]) Scan(value any) error {
if value == nil {
*o = Option[T]{}
return nil
}
// 使用类型断言而不是反射
switch v := value.(type) {
case int64:
*o = Option[T]{
value: T(v), // 类型转换
isSome: true,
}
case string:
*o = Option[T]{
value: T(v),
isSome: true,
}
case bool:
*o = Option[T]{
value: T(v),
isSome: true,
}
case float64:
*o = Option[T]{
value: T(v),
isSome: true,
}
default:
// 处理 sql.Null 类型
switch val := value.(type) {
case sql.NullInt64:
if val.Valid {
*o = Option[T]{
value: T(val.Int64),
isSome: true,
}
} else {
*o = Option[T]{}
}
case sql.NullString:
if val.Valid {
*o = Option[T]{
value: T(val.String),
isSome: true,
}
} else {
*o = Option[T]{}
}
default:
return &sql.ScanError{}
}
}
return nil
}
// Value 方法的实现
func (o Option[T]) Value() (driver.Value, error) {
if !o.isSome {
return nil, nil
}
return o.value, nil
}
如果你需要支持更多类型,可以扩展 Scannable 约束:
type Scannable interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64 |
~string | ~bool
}
// 使用示例
func main() {
var optInt Option[int64]
optInt.Scan(int64(42))
var optStr Option[string]
optStr.Scan("hello")
var optBool Option[bool]
optBool.Scan(true)
}
对于数据库操作,你可能还需要实现 driver.Valuer 接口:
func (o Option[T]) Value() (driver.Value, error) {
if !o.isSome {
return nil, nil
}
return o.value, nil
}
这样你的 Option 类型就可以在数据库操作中正确使用了。

