Go语言有函数/方法重载吗?

发布于 2024-11-28 06:49:04 字数 807 浏览 2 评论 0 原文

我正在将 C 库移植到 Go。 C 函数(带有可变参数)的定义如下:

curl_easy_setopt(CURL *curl, CURLoption option, ...); 

所以我创建了包装 C 函数:

curl_wrapper_easy_setopt_str(CURL *curl, CURLoption option, char* param);
curl_wrapper_easy_setopt_long(CURL *curl, CURLoption option, long param);

如果我在 Go 中定义函数如下:

func (e *Easy)SetOption(option Option, param string) {
    e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(param)))
}

func (e *Easy)SetOption(option Option, param long) {
    e.code = Code(C.curl_wrapper_easy_setopt_long(e.curl, C.CURLoption(option), C.long(param)))
}

Go 编译器抱怨:

*Easy·SetOption redeclared in this block

那么 Go 是否支持函数(方法)重载,或者这个错误是否意味着其他含义?

I'm porting a C library to Go. A C function (with varargs) is defined like this:

curl_easy_setopt(CURL *curl, CURLoption option, ...); 

So I created wrapper C functions:

curl_wrapper_easy_setopt_str(CURL *curl, CURLoption option, char* param);
curl_wrapper_easy_setopt_long(CURL *curl, CURLoption option, long param);

If I define function in Go like this:

func (e *Easy)SetOption(option Option, param string) {
    e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(param)))
}

func (e *Easy)SetOption(option Option, param long) {
    e.code = Code(C.curl_wrapper_easy_setopt_long(e.curl, C.CURLoption(option), C.long(param)))
}

The Go compiler complains:

*Easy·SetOption redeclared in this block

So does Go support function (method) overloading, or does this error mean something else?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

心碎的声音 2024-12-05 06:49:04

不,事实并非如此。

请参阅 Go 语言常见问题解答,特别是关于 重载

如果方法分派也不需要进行类型匹配,那么它就会被简化。其他语言的经验告诉我们,使用具有相同名称但不同签名的多种方法有时是有用的,但在实践中也可能会造成混乱和脆弱。仅按名称匹配并要求类型一致是 Go 类型系统中的一个重大简化决策。

更新:2016-04-07

虽然 Go 仍然没有重载函数(可能永远不会),但重载最有用的功能,即使用可选参数调用函数并推断省略参数的默认值,可以使用可变参数函数进行模拟,此后已添加。但这是在类型检查丢失的情况下实现的。

No it does not.

See the Go Language FAQ, and specifically the section on overloading.

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.

Update: 2016-04-07

While Go still does not have overloaded functions (and probably never will), the most useful feature of overloading, that of calling a function with optional arguments and inferring defaults for those omitted can be simulated using a variadic function, which has since been added. But this comes at the loss of type checking.

听你说爱我 2024-12-05 06:49:04

据此,它没有: http://golang.org/doc/go_for_cpp_programmers.html

概念差异部分中,它说:

Go 不支持函数重载,也不支持用户定义的运算符。

According to this, it doesn't: http://golang.org/doc/go_for_cpp_programmers.html

In the Conceptual Differences section, it says:

Go does not support function overloading and does not support user defined operators.

人心善变 2024-12-05 06:49:04

不,Go 没有重载。

重载会增加编译器的复杂性,并且可能永远不会被添加。

正如 Lawrence Dol 提到的,您可以使用可变参数函数,但代价是不进行类型检查。

最好的选择是使用 泛型类型约束 rel="noreferrer">Go 1.18

为了回答 VityaSchel 的问题,在 Lawrence 的答案的评论中,如何创建一个通用的求和函数,我在下面写了一个。

https://go.dev/play/p/hRhInhsAJFT


package main

import "fmt"

type Number interface {
  int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64
}

func Sum[number Number](a number, b number) number {
  return a + b
}

func main() {
  var a float64 = 5.1
  var b float64 = 3.2
  println(Sum(a, b))

  var a2 int = 5
  var b2 int = 3
  println(Sum(a2, b2))
}

No, Go doesn't have overloading.

Overloading adds compiler complexity and will likely never be added.

As Lawrence Dol mentioned, you could use a variadic function at the cost of no type checking.

Your best bet is to use generics and type constraints that were added in Go 1.18

To answer VityaSchel's question, in the comments of Lawrence's answer, of how to make a generic sum function, I've written one below.

https://go.dev/play/p/hRhInhsAJFT


package main

import "fmt"

type Number interface {
  int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64
}

func Sum[number Number](a number, b number) number {
  return a + b
}

func main() {
  var a float64 = 5.1
  var b float64 = 3.2
  println(Sum(a, b))

  var a2 int = 5
  var b2 int = 3
  println(Sum(a2, b2))
}

佼人 2024-12-05 06:49:04

尽管这个问题确实很老了,但我仍然想说的是,有一种方法可以实现接近重载函数的效果。尽管它可能不会使代码变得如此易于阅读。

假设您想重载函数Test()

func Test(a int) {
    println(a);
}
func Test(a int, b string) {
    println(a);
    println(b);
}

上面的代码将导致错误。但是,如果您将第一个 Test() 重新定义为 Test1(),将第二个重新定义为 Test2(),并定义一个新函数 Test() 使用 go 的 ...,您将能够以重载的方式调用函数 Test()
代码:

package main;

func Test1(a int) {
    println(a);
}
func Test2(a int, b string) {
    println(a);
    println(b);
}
func Test(a int, bs ...string) {
    if len(bs) == 0 {
        Test1(a);
    } else {
        Test2(a, bs[0]);
    }
}
func main() {
    Test(1);
    Test(1, "aaa");
}

输出:

1
1
aaa

查看更多信息: https://golangbyexample.com/function-method-overloading -golang/ (我不是这篇链接文章的作者,但我个人认为它很有用)

Even though this question is really old, what I still want to say is that there is a way to acheive something close to overloading functions. Although it may not make the code so easy to read.

Say if you want to overload the funtion Test():

func Test(a int) {
    println(a);
}
func Test(a int, b string) {
    println(a);
    println(b);
}

The code above will cause error. However if you redefine the first Test() to Test1() and the second to Test2(), and define a new function Test() using go's ..., you would be able to call the function Test() the way it is overloaded.
code:

package main;

func Test1(a int) {
    println(a);
}
func Test2(a int, b string) {
    println(a);
    println(b);
}
func Test(a int, bs ...string) {
    if len(bs) == 0 {
        Test1(a);
    } else {
        Test2(a, bs[0]);
    }
}
func main() {
    Test(1);
    Test(1, "aaa");
}

output:

1
1
aaa

see more at: https://golangbyexample.com/function-method-overloading-golang/ (I'm not the author of this linked article but personally consider it useful)

羅雙樹 2024-12-05 06:49:04

您还可以通过使用 ...interface{} 使函数可变参数来实现此目的,这将使 param 为 Slice 类型,
然后使用 param[0] 去掉其中的第一个值,

func (e *Easy)SetOption(option Option, param ...interface{}) {
    e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(param[0])))
}

现在任何类型的参数都是有效的,但以类型检查为代价

You can also do it by making the function variadic using ...interface{}, this will make the param as of type Slice,
and then just take off the first value in it using param[0]

func (e *Easy)SetOption(option Option, param ...interface{}) {
    e.code = Code(C.curl_wrapper_easy_setopt_str(e.curl, C.CURLoption(option), C.CString(param[0])))
}

now argument of any type is valid, but at the cost of type checking

烟酉 2024-12-05 06:49:04

正如其他人所说,答案是否定的!

但是 Golang 提供了另一个称为接收器的功能,它可以用来编写接近重载的东西:

基本上,我们使用接收器作为区分函数的一种方式,并且能够<强>对两个不同的函数使用相同的函数名,它们可以具有相同的参数或差异参数,但唯一需要注意的是,您只能使用接收器附加来调用该函数!

我怀疑这种代码是否有用,因为它可能会令人困惑,但尽管如此,它是可能的:)

package main

import "fmt"

type hello struct {
    name string
}

func main() {
    fmt.Println(returnNumber(777))
    h := hello{name: "hello"}
    fmt.Println(h.returnNumber("world"))
}

func returnNumber(i int) int {
    return i
}

func (h hello) returnNumber(s string) string {
    return h.name + s
}

As others said the answer is No!

But Golang provides another feature called as receivers which can be used to write something close to overloading:

Basically we are using receiver as a way to differentiate the functions and are able to use same function name for two different functions which can have same args or diff args, but the only caveat is that you can invoke the function only with receiver as its attached to it !

I doubt this kind of code could be useful as it can be confusing, but nevertheless its possible :)

package main

import "fmt"

type hello struct {
    name string
}

func main() {
    fmt.Println(returnNumber(777))
    h := hello{name: "hello"}
    fmt.Println(h.returnNumber("world"))
}

func returnNumber(i int) int {
    return i
}

func (h hello) returnNumber(s string) string {
    return h.name + s
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文