Golang中具有相同名称和参数个数但类型不同的方法

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

Golang methods with same name and arity, but different type

问题

以下代码运行正常。两个方法分别操作两个不同的结构体,并打印结构体的一个字段:

type A struct {
  Name string
}

type B struct {
  Name string
}

func (a *A) Print() {
  fmt.Println(a.Name)
}

func (b *B) Print() {
  fmt.Println(b.Name)
}

func main() {
  a := &A{"A"}
  b := &B{"B"}

  a.Print()
  b.Print()
}

在控制台上显示所期望的输出:

A
B

现在,如果我按以下方式更改方法签名,我会得到一个编译错误。我只是将方法的接收器移到了方法的参数中:

func Print(a *A) {
  fmt.Println(a.Name)
}

func Print(b *B) {
  fmt.Println(b.Name)
}

func main() {
  a := &A{"A"}
  b := &B{"B"}

  Print(a)
  Print(b)
}

我甚至无法编译这个程序:

./test.go:22: Print redeclared in this block
    previous declaration at ./test.go:18
./test.go:40: cannot use a (type *A) as type *B in function argument

为什么当方法具有相同的名称和参数个数时,我可以在接收器中交换结构体类型,但在参数中却不能交换呢?

英文:

The following code works fine. Two methods operating on two different structs and printing a field of the struct:

type A struct {
  Name string
}

type B struct {
  Name string
}

func (a *A) Print() {
  fmt.Println(a.Name)
}

func (b *B) Print() {
  fmt.Println(b.Name)
}

func main() {

  a := &A{"A"}
  b := &B{"B"}

  a.Print()
  b.Print()
}

Shows the desired output in the console:

A
B

Now, if I change the method signature in the following way I get an compile error. I just move the receiver of the method to the arguments of the method:

func Print(a *A) {
  fmt.Println(a.Name)
}

func Print(b *B) {
  fmt.Println(b.Name)
}

func main() {

  a := &A{"A"}
  b := &B{"B"}

  Print(a)
  Print(b)
}

I can't even compile the program:

./test.go:22: Print redeclared in this block
    previous declaration at ./test.go:18
./test.go:40: cannot use a (type *A) as type *B in function argument

Why is it that I can interchange struct types in the receiver, but not in the
arguments, when the methods have the same name and arity?

答案1

得分: 52

因为Go语言不支持根据参数类型对用户定义的函数进行重载。

你可以使用不同名称的函数,或者如果你只想在一个参数(接收者)上进行“重载”,可以使用方法。

英文:

Because Go does not support overloading of user-defined functions on their argument types.

You can make functions with different names instead, or use methods if you want to "overload" on only one parameter (the receiver).

答案2

得分: 12

你可以使用类型反射(type introspection)。不过,一般情况下,应该避免使用通用的interface{}类型,除非你正在编写一个大型的通用框架。

有几种方法可以实现相同的效果:

这两种方法都假设*A*B类型都定义了Print()方法。

方法1:

func Print(any interface{}) {
    switch v := any.(type) {
    case *A:
        v.Print()
    case *B:
        v.Print()
    default:
        fmt.Printf("Print()调用了不支持的类型:%T(期望的类型是*A或*B)\n", any)
        return
    }
}

方法2:

type Printer interface {
    Print()
}

func Print(any interface{}) {
    // 检查传入的值是否符合Printer接口
    if v, ok := any.(Printer); ok {
        // 是的话,调用Print()方法
        v.Print()
    } else {
        fmt.Printf("传入的值的类型为%T,没有Print()方法。\n", any)
        return
    }
}

如果不希望为每种类型都定义一个Print()方法,可以定义针对*A*B类型的PrintA(*A)PrintB(*B)函数,并修改方法1,如下所示:

case *A:
    PrintA(v)
case *B:
    PrintB(v)

你可以在这里找到一个可运行的示例。

英文:

You can use type introspection. As a general rule, though, any use of the generic interface{} type should be avoided, unless you are writing a large generic framework.

That said, a couple of ways to skin the proverbial cat:

Both methods assume a Print() method is defined for both types (*A and *B)

Method 1:

func Print(any interface{}) {
	switch v := any.(type) {
	case *A:
		v.Print()
	case *B:
		v.Print()
	default:
		fmt.Printf("Print() invoked with unsupported type: '%T' (expected *A or *B)\n", any)
		return
	}
}

Method 2:

type Printer interface {
	Print()
}

func Print(any interface{}) {
	// does the passed value honor the 'Printer' interface
	if v, ok := any.(Printer); ok {
		// yes - so Print()!
		v.Print()
	} else {
		fmt.Printf("value of type %T passed has no Print() method.\n", any)
		return
	}
}

If it's undesirable to have a Print() method for each type, define targeted PrintA(*A) and PrintB(*B) functions and alter Method 1 like so:

    case *A:
        PrintA(v)
    case *B:
        PrintB(v)

Working playground example here.

答案3

得分: 1

在Go语言中,无法进行函数或方法的重载。虽然可以在Go中拥有两个同名的方法,但这些方法的接收者类型必须不同。你可以在这个链接中了解更多信息。

英文:

You can not do function or method overloading in Go. You can have two methods with the same names in Go but the receiver of these methods must be of different types.
you can see more in this link .

huangapple
  • 本文由 发表于 2014年5月15日 22:55:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/23681871.html
匿名

发表评论

匿名网友

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

确定