How can I write a function that takes either one of many types in go?

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

How can I write a function that takes either one of many types in go?

问题

我正在尝试进行一个小项目,并尝试编写以下函数:

func fatal(reason string) {
    println(reason)
    os.Exit(1)
}

func fatal(err error) {
    fatal(err.Error())
}

在查找了一些资料并找到了这个答案后,它引用了关于重载的文档,我意识到我在尝试做的事在 Go 语言中是不合法的。

我想要的是一个简单的 API,允许我使用字符串或错误调用 fatal 函数,以简化我的逻辑。我该如何实现这个目标或类似的目标?

如果我同时拥有 func fatal(reason string)func fatalErr(err error),会感觉不够优雅,这是必需的吗?我是否错过了语言中允许我实现所需功能的其他特性?

英文:

I'm trying go for a small project and tried to write these functions:

func fatal(reason string) {
	println(reason)
	os.Exit(1)
}

func fatal(err error) {
	fatal(err.Error())
}

After digging about a bit and finding this answer, which referenced the docs on overloading I realised that what I was trying to do was illegal in go.

What I want is a simple api that allows me to call fatal with either a string or an error in order to simplify my logic. How do I achieve this or a similar goal?

It would feel inelegant to have func fatal(reason string) along with func fatalErr(err error), is that what's needed? Am I missing a different feature of the language that allows me to do what I want?

答案1

得分: 3

最常见的方法是将方法定义为func fatal(err interface{}),然后在其内部使用类型断言或类型切换来处理不同类型的错误。如果我为你的示例编写代码,它会像这样:

func fatal(err interface{}) {
    if v, ok := err.(string); ok {
        fmt.Println(v)
    }
    if v, ok := err.(error); ok {
        fmt.Println(v.Error())
    } else {
        // 处理 panic?
    }
}

此外,这是一个关于类型切换和断言的快速阅读,可能会有所帮助:http://blog.denevell.org/golang-interface-type-assertions-switch.html。你还可以查看《Effective Go》,它有关于这两个特性的章节。

英文:

The most common way to do this would be to define the method as func fatal(err interface{}) then do type assertions or use a type switch within it's body to handle each of the different types. If I were coding for your example it would look like this;

func fatal(err interface{}) {
     if v, ok := err.(string); ok {
         fmt.Println(v)
     }
     if v, ok := err.(error); ok {
          fmt.Println(v.Error())
     } else {
        // panic ?
     }
}

Also; here's a quick read about type switches and assertions that may be helpful; http://blog.denevell.org/golang-interface-type-assertions-switch.html
You can also check out effective-go as it has sections on both features.

答案2

得分: 2

使用log.Fatal()代替。https://golang.org/pkg/log/#Fatal

你可以使用interface{},但不建议这样做,因为这样会失去类型检查的所有好处。Go的作者可以使用interface{},因为他们理解在使用interface{}时需要进行适当级别的额外测试和检查。当需要类似功能时,即使对于中级和高级的Go开发者来说,使用内置和标准库函数也要容易得多。

Go也没有代数类型或和/或类型。标准的解决方法是使用指针定义一个与类型相关的结构体(例如struct{*string, *error}),并努力确保在任何时候只有一个字段非nil。

英文:

Use log.Fatal() instead. https://golang.org/pkg/log/#Fatal

You can use interface{} but it is not recommended because you lose all the benefits of type checking when you do that. The Go authors get to use interface{} because they understand the appropriate level of additional testing and checks to do when using interface{}. It's much easier (even for intermediate and advanced gophers) to use builtin and standard library functions when something like this is required.

Go does not have algebraic or/sum types either. The standard workaround is to define an and/product type with pointers (e.g. struct{*string, *error}) and go to the effort of making sure you only ever make one of the fields non nil at any point in time.

答案3

得分: 0

函数重载在该语言中不受支持。根据官方的Golang网站上的说法,

如果方法调度不需要进行类型匹配,那么方法调度就会变得简化。从其他语言的经验来看,拥有多个具有相同名称但不同签名的方法有时很有用,但在实践中可能会令人困惑和脆弱。只通过名称匹配并要求类型一致是Go类型系统中的一个重要简化决策。

关于运算符重载,它似乎更多是一种便利而不是绝对要求。同样,没有它会更简单。

https://golang.org/doc/faq#overloading

一个潜在的解决方案是定义一个高级函数,该函数对不同类型进行类型检查并以类似于重载多个函数的方式处理它们。请参考@evanmcdonnal的解决方案,这是一个很好的例子。

英文:

Function overloading is not supported in the language. From the official Golang site it says,

<blockquote>Method dispatch is simplified if it doesn't need to do type matching as well. Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.

Regarding operator overloading, it seems more a convenience than an absolute requirement. Again, things are simpler without it.</blockquote>

https://golang.org/doc/faq#overloading

One potential solution would be to define a high level function that type checks and handles different types similarly to how you would overload multiple functions. See @evanmcdonnal's solution for a great example.

huangapple
  • 本文由 发表于 2015年12月22日 08:33:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/34406700.html
匿名

发表评论

匿名网友

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

确定