在Go语言中传递任意类型的惯用方式(同时保持编译时类型检查)是什么?

huangapple go评论74阅读模式
英文:

Idiomatic way to pass any type in Go (while keeping compile time type-checking?)

问题

我正在解析一个表单,并编写了一些函数 func parseAndValidateX(val string) (T, err),其中 T 是任意类型。

现在我想编写一个闭包 func catchError(T, Error) T,这样我就可以像这样做:

errors []Error

func catchError(val T, err Error) T {
    if err != nil {
        // 将 err 添加到 errors
    }
    return val
}


data = MyStruct {
    Age = catchError(parseAndValidateAge("5")) // Age 是一个 int
    DistanceFromHome = catchError(parseAndValidatePi("3.14")) // DistanceFromHome 是一个 float
    Location = catchError(parseAndValidatePi("3.14,2.0")) // Location 是一个自定义结构体
}

if len(errors) > 0 {
    // 哦,出错了
}

在 Go 中是否可能实现这个功能?如何以简单/惯用的方式实现?

英文:

I am parsing a form and have written a number of functions func parseAndValidateX(val string) (T, err) where T is any type.

Now I would like to write a closure func catchError(T, Error) T, so that I can do something like:

errors []Error

func catchError(val T, err Error) T {
    if err != nil {
        //append err to errors
    }
    return val
}


data = MyStruct {
Age = catchError(parseAndValidateAge("5")) // Age is a int
DistanceFromHome = catchError(parseAndValidatePi("3.14")) // DistanceFromHome is a float
Location = catchError(parseAndValidatePi("3.14,2.0")) //Location is a custom Struct
}

if len(errors) > 0 {
    // o, oh
}

Is this possible in Go? How can this be done easily/idiomatically?

答案1

得分: 7

不行,因为Go语言对于用户定义的函数没有参数多态性。你只能使用interface{}来接收和返回值,并在调用处添加类型断言。

如果你不使用unsafe包,Go语言中的所有内容都是类型安全的,所以你不必担心这个问题。类型断言会在运行时而不是编译时失败。

不过,如果你愿意违反DRY原则,可以这样做:

type errorList []Error

func (l *errorList) addIfNotNil(err Error) {
    if err != nil {
        *l = append(*l, err)
    }
}

func (l *errorList) int(x int, err Error) int {
    l.addIfNotNil(err)
    return x
}

func (l *errorList) float32(x float32, err Error) float32 {
    l.addIfNotNil(err)
    return x
}

list := errorList([]Error{})
data := MyStruct{
    Age: list.int(parseAndValidateAge("5")),
    DistanceFromHome: list.float32(parseAndValidatePi("3.14")),
}

以上是一个可能的解决方案。

英文:

Nope; you cannot do that since Go has no parametric polymorphism for user-defined functions. All you can do is take and return interface{} and add type assertions at the call sites.

Everything in Go is type-safe if you don't use the unsafe package, so you don't have to worry about that. A type assertion will fail at runtime instead of at compile-time, though.

If you are willing to violate DRY, though:

type errorList []Error

func (l *errorList) addIfNotNil(err Error) {
    if err != nil {
        *l = append(*l, err)
    }
}

func (l *errorList) int(x int, err Error) int {
    l.addIfNotNil(err)
    return x
}

func (l *errorList) float32(x float32, err Error) float32 {
    l.addIfNotNil(err)
    return x
}

list := errorList([]Error{})
data := MyStruct{
    Age: list.int(parseAndValidateAge("5")),
    DistanceFromHome: list.float32(parseAndValidatePi("3.14")),
}

huangapple
  • 本文由 发表于 2014年12月11日 17:00:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/27418877.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定