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

时间:2011-11-24 23:44:47

标签: function methods go

我正在尝试开始使用Go,documentation非常好。我在文档中没有找到的是函数和方法之间的区别。

据我所知,目前:函数是“全局的”,这意味着我不必导入包来使用函数,它们总是在那里。方法绑定到包。这是对的吗?

3 个答案:

答案 0 :(得分:75)

  

据我所知,目前:函数是“全局的”,这意味着我不必导入包来使用函数,它们总是在那里。方法绑定到包。这是对的吗?

不,那不对。 builtin包中只有几个函数可以随时使用。其他一切都需要进口。

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

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

所以,例如:

func MyFunction(a, b int) int {
  return a + b
}
// Usage:
// MyFunction(1, 2)

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

答案 1 :(得分:13)

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

type Triangle struct {
    a, b, c float64
}

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

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
}

现在你得到了你的工作程序 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
}

我们有一个完全 working example

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

答案 2 :(得分:8)

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

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

func FunctionName(Parameters...) ReturnTypes...

示例:

func add(x int, y int) int

执行:

  add(2,3) 

方法就像一个函数,但附加到一个类型(称为接收器)。官方指南指出“方法是具有特殊接收器参数的函数”。接收器出现在func关键字和方法名称之间。方法的语法是:

func (t ReceiverType) FunctionName(Parameters...) ReturnTypes...

示例:

func (t MyType) add(int x, int y) int

执行:

type MyType string
t1 := MyType("sample")
t1.add(1,2)

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

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

func FunctionName(*Pointers...,Parameters...) ReturnTypes...

实施例

func add(t *MyType, x int, y int) int

执行:

type MyType string
t1 := MyType("sample")
add(&t1,4,5)

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

func (*Pointer) FunctionName(Parameters...) ReturnTypes...

实施例

func (t *MyType) add(x int, y int) int

执行:

type MyType string
t1 := MyType("sample")
t1.add(2,3)

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

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