英文:
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")),
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论