Golang方法具有相同的名称和arity,但类型不同

Kir*_*ril 20 methods struct go

以下代码工作正常.两种方法在两个不同的结构上运行并打印结构的一个字段:

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()
}
Run Code Online (Sandbox Code Playgroud)

在控制台中显示所需的输出:

A
B
Run Code Online (Sandbox Code Playgroud)

现在,如果我按以下方式更改方法签名,则会出现编译错误.我只是将方法的接收者移动到方法的参数:

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)
}
Run Code Online (Sandbox Code Playgroud)

我甚至无法编译程序:

./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
Run Code Online (Sandbox Code Playgroud)

问题:方法具有相同的名称和arity ,为什么我可以在接收器中交换结构类型,而不是在参数中交换结构类型?

rig*_*old 35

因为Go不支持在其参数类型上重载用户定义的函数.

您可以使用不同的名称来创建函数,或者如果您只想对一个参数(接收器)"重载",则使用方法.


col*_*tor 9

您可以使用类型自省。但是,作为一般规则,interface{}应避免使用泛型类型,除非您正在编写大型泛型框架。

也就是说,有几种方法可以给众所周知的猫剥皮:

两种方法都假定为两种类型(和)定义了 Print()方法*A*B

方法一:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

方法二:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

如果不希望为每种类型都有一个Print() 方法,请定义目标PrintA(*A)PrintB(*B) 函数并像这样更改方法 1:

    case *A:
        PrintA(v)
    case *B:
        PrintB(v)
Run Code Online (Sandbox Code Playgroud)

工作操场示例在这里