Golang methods with same name and arity, but diffe

2019-04-18 05:39发布

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

Question: 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?

2条回答
贪生不怕死
2楼-- · 2019-04-18 06:00

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).

查看更多
地球回转人心会变
3楼-- · 2019-04-18 06:10

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.

查看更多
登录 后发表回答