什么是Go中的功能和方法的区别?

Dom*_*ier 46 methods function go

我想开始使用Go并且文档非常好.我在文档中没有找到的是函数和方法之间的区别.

据我所知,目前:函数是"全局的",这意味着我不必导入包来使用函数,它们总是在那里.方法绑定到包.它是否正确?

tux*_*21b 84

据我所知,目前:函数是"全局的",这意味着我不必导入包来使用函数,它们总是在那里.方法绑定到包.它是否正确?

不,那不对.内置程序包中只有几个功能始终可用.其他一切都需要进口.

术语"方法"提出了面向对象的编程.在OOP语言(例如C++)中,您可以定义一个"类",它封装了属于一起的数据和函数.类中的这些函数称为"方法",您需要该类的实例来调用此类方法.

在Go中,术语基本相同,尽管Go不是经典意义上的OOP语言.在Go中,接收接收器的函数通常被称为方法(可能仅仅因为人们习惯于OOP的术语).

所以,例如:

func MyFunction(a, b int) int {
  return a + b
}
// Usage:
// MyFunction(1, 2)
Run Code Online (Sandbox Code Playgroud)

type MyInteger int
func (a MyInteger) MyMethod(b int) int {
  return a + b
}
// Usage:
// var x MyInteger = 1
// x.MyMethod(2)
Run Code Online (Sandbox Code Playgroud)

  • 我不会说"Go不是OOP语言".去恕我直言,只是偏爱继承的成分,以至于它为前者提供额外的合成糖,并完全摆脱了后者. (5认同)
  • 对此我不确定.Imho,OOP范例的一部分也是子类+类型层次结构.这对Go来说是不可能的(幸运的是!).当然,Go提供其他方法(即嵌入)来解决类似问题,但它们不是1:1的替代品.但是,让我们停止术语 - 自行车:D (4认同)
  • 谢谢,我终于明白了!缺少的是,方法总是与类型一起使用. (4认同)
  • @ tux21b谢谢你的例子.一个问题,你的方法包含一个`无效的操作:a + b(不匹配的类型MyInteger和int)`.为了实现这一点,你需要将`a`转换为`int`或`b`作为`MyInteger`.例如:`return int(a)+ b`或`return a + MyInteger(b)`.在第二种情况下,您需要将方法签名中的返回值类型更改为"MyInteger"而不是"int".[游乐场](http://play.golang.org/p/tVlSCnkbx5) (4认同)

Sal*_*ali 16

Tux的答案很棒,但是我希望通过使用Go的方法来增加它struct(因为这是我经常使用它的地方).因此,我们假设你想构建一些东西来计算三角形上的各种方法.你从一开始struct:

type Triangle struct {
    a, b, c float64
}
Run Code Online (Sandbox Code Playgroud)

然后你想添加一些函数来计算周长和平方:

func valid(t *Triangle) error {
    if t.a + t.b > t.c && t.a + t.c > t.b && t.b + t.c > t.a {
        return nil
    }
    return errors.New("Triangle is not valid")
}

func perimeter(t *Triangle) (float64, error) {
    err := valid(t)
    if err != nil {
        return -1, err
    }

    return t.a + t.b + t.c, nil
}

func square(t *Triangle) (float64, error) {
    p, err := perimeter(t)
    if err != nil {
        return -1, err
    }

    p /= 2
    s := p * (p - t.a) * (p - t.b) * (p - t.c)
    return math.Sqrt(s), nil
}
Run Code Online (Sandbox Code Playgroud)

现在你得到了你的工作计划Go Playground.在这种情况下,您的函数接受一个参数(指向三角形的指针)并执行某些操作.在OOP中,人们可能创建了一个类,然后添加了方法.我们可以看到我们的struct作为带有字段的类,现在我们添加方法:

func (t *Triangle) valid() error {
    if t.a + t.b > t.c && t.a + t.c > t.b && t.b + t.c > t.a {
        return nil
    }
    return errors.New("Triangle is not valid")
}

func (t *Triangle) perimeter() (float64, error) {
    err := t.valid()
    if err != nil {
        return -1, err
    }

    return t.a + t.b + t.c, nil
}

func (t *Triangle) square() (float64, error) {
    p, err := t.perimeter()
    if err != nil {
        return -1, err
    }

    p /= 2
    s := p * (p - t.a) * (p - t.b) * (p - t.c)
    return math.Sqrt(s), nil
}
Run Code Online (Sandbox Code Playgroud)

我们有一个完整的working example.

请注意,它看起来非常像对象的方法.


小智 9

这里详细解释了它们 - https://anil.cloud/2017/01/26/golang-functions-methods-simplified/

Go中的函数遵循以下语法:

func FunctionName(Parameters...) ReturnTypes...
Run Code Online (Sandbox Code Playgroud)

例:

func add(x int, y int) int
Run Code Online (Sandbox Code Playgroud)

执行:

  add(2,3) 
Run Code Online (Sandbox Code Playgroud)

方法类似于函数,但附加到类型(称为接收器).官方指南指出"方法是具有特殊接收器参数的函数".接收器出现在func关键字和方法名称之间.方法的语法是:

func (t ReceiverType) FunctionName(Parameters...) ReturnTypes...
Run Code Online (Sandbox Code Playgroud)

例:

func (t MyType) add(int x, int y) int
Run Code Online (Sandbox Code Playgroud)

执行:

type MyType string
t1 := MyType("sample")
t1.add(1,2)
Run Code Online (Sandbox Code Playgroud)

现在让我们把指针带到表中.Go lang是按值传递的,意味着参数的新副本被传递给每个函数/方法调用.要通过引用传递它们,您可以使用指针.

参数/参数列表中带指针的函数语法.

func FunctionName(*Pointers...,Parameters...) ReturnTypes...
Run Code Online (Sandbox Code Playgroud)

func add(t *MyType, x int, y int) int
Run Code Online (Sandbox Code Playgroud)

执行:

type MyType string
t1 := MyType("sample")
add(&t1,4,5)
Run Code Online (Sandbox Code Playgroud)

类似地,对于方法,接收器类型可以是指针.带指针的方法语法(作为接收器)

func (*Pointer) FunctionName(Parameters...) ReturnTypes...
Run Code Online (Sandbox Code Playgroud)

func (t *MyType) add(x int, y int) int
Run Code Online (Sandbox Code Playgroud)

执行:

type MyType string
t1 := MyType("sample")
t1.add(2,3)
Run Code Online (Sandbox Code Playgroud)

请注意,我们仍然可以编写t1.add()来使用指针接收器执行该方法(即使't1'不是指针),Go会将其解释为(&t1).add().类似地,也可以使用指针调用带有值接收器的方法,在这种情况下,Go会将p.add()解释为(*p).add()(其中'p'是指针).这仅适用于方法而不适用于功能.

具有指针接收器的方法对于获得类似"Java"的行为非常有用,其中该方法实际上修改接收器指向的值而不是其副本.