Go中函数和方法的区别是什么?

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

Whats the difference of functions and methods in Go?

问题

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

据我目前的理解:函数是“全局”的,这意味着我不需要导入包就可以使用函数,它们总是存在的。而方法是绑定到包的。这样理解对吗?

英文:

I am trying to get started with Go and the documentation is very good. What I did not find in the documentation is the difference between functions and methods.

As far as I understand at the moment: functions are "global", which means I do not have to import a package to use functions, they are always there. Methods are bound to packages. Is this correct?

答案1

得分: 133

根据我目前的理解:函数是“全局”的,这意味着我不需要导入包来使用函数,它们总是存在的。方法是绑定到包的。这正确吗?

不,这是不正确的。只有一些来自builtin包的函数是始终可用的。其他所有内容都需要导入。

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

在Go中,术语基本上是相同的,尽管Go不是传统意义上的面向对象编程语言。在Go中,一个带有接收器的函数通常被称为方法(可能只是因为人们仍然习惯于面向对象编程的术语)。

所以,例如:

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

但是

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

> As far as I understand at the moment: functions are "global", which means I do not have to import a package to use functions, they are always there. Methods are bound to packages. Is this correct?

No, that's not correct. There are just a couple of functions from the builtin package which are always available. Everything else needs to be imported.

The term "method" came up with object-oriented programming. In an OOP language (like C++ for example) you can define a "class" which encapsulates data and functions which belong together. Those functions inside a class are called "methods" and you need an instance of that class to call such a method.

In Go, the terminology is basically the same, although Go isn't an OOP language in the classical meaning. In Go, a function which takes a receiver is usually called a method (probably just because people are still used to the terminology of OOP).

So, for example:

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

but

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

答案2

得分: 32

Tux的回答很好,但我想通过使用Go的struct方法来增强它(因为我经常使用它)。所以让我们假设你想构建一个用于计算三角形各种方法的东西。你可以从一个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
}

现在你有了一个工作的程序<kbd>Go Playground</kbd>。在这种情况下,你的函数接受一个参数(指向三角形的指针)并执行某些操作。在面向对象编程中,人们可能会创建一个类,然后添加方法。我们可以将我们的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
}

现在我们有了一个完整的<kbd>工作示例</kbd>。

请注意,它看起来确实像是对象的方法。

英文:

Tux's answer is great, but I want to augment it with the usage of Go's methods with structs (because this is where I used it often). So let's assume you want to build something to calculate various methods on triangles. You start with a struct:

type Triangle struct {
    a, b, c float64
}

and then you would like to add some functions to calculate the perimeter and square:

func valid(t *Triangle) error {
	if t.a + t.b &gt; t.c &amp;&amp; t.a + t.c &gt; t.b &amp;&amp; t.b + t.c &gt; t.a {
		return nil
	}
	return errors.New(&quot;Triangle is not valid&quot;)
}

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
}

And now you got your working program <kbd>Go Playground</kbd>. In this case your function takes a parameter (pointer to a triangle) and does something. In OOP word people might have created a class and then added methods. We can see our struct as kind of class with fields and now we add methods:

func (t *Triangle) valid() error {
	if t.a + t.b &gt; t.c &amp;&amp; t.a + t.c &gt; t.b &amp;&amp; t.b + t.c &gt; t.a {
		return nil
	}
	return errors.New(&quot;Triangle is not valid&quot;)
}

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
}

and we have a fully <kbd>working example</kbd>.

Notice that it looks really like a method for objects.

答案3

得分: 22

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

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

func 函数名(参数...) 返回类型...

示例:

func add(x int, y int) int

执行:

  add(2,3) 

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

func (t 接收器类型) 函数名(参数...) 返回类型...

示例:

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

执行:

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

现在让我们将指针引入到表中。Go语言是按值传递的,这意味着每个函数/方法调用都会传递参数的新副本。要通过引用传递它们,可以使用指针。

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

func 函数名(*指针...,参数...) 返回类型...

示例

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

执行:

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

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

func (*指针) 函数名(参数...) 返回类型...

示例

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”的行为,其中方法实际上是在修改接收器指向的值,而不是在副本上进行修改。

英文:

They are explained in detail here - https://anil.cloud/2017/01/26/golang-functions-methods-simplified/

A function in Go follows the syntax:

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

Example:

func add(x int, y int) int

To execute:

  add(2,3) 

A method is like a function, but attached to a type (called as receiver). The official guide states “A method is a function with a special receiver argument”. The receiver appears in between the func keyword and the method name. The syntax of a method is:

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

Example:

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

To execute:

type MyType string
t1 := MyType(&quot;sample&quot;)
t1.add(1,2)

Now lets bring pointers into the table. Go lang is pass by value, means fresh copies of the parameters are passed to each function/method call. To pass them by reference you can use pointers.

Syntax of function with pointer in argument/parameter list.

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

Example

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

To execute:

type MyType string
t1 := MyType(&quot;sample&quot;)
add(&amp;t1,4,5)

Similarly for methods, the receiver type can be a pointer. Syntax of method with pointer (as receiver)

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

Example

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

To execute:

type MyType string
t1 := MyType(&quot;sample&quot;)
t1.add(2,3)

Note that we can still write t1.add() to execute the method with a pointer receiver(even-though ‘t1’ is not a pointer) and Go will interpret it as (&t1).add(). Similarly a method with value receiver can be called using pointer too, Go will interpret p.add() as as (*p).add() in that case (where ‘p’ is a pointer). This is applicable only for methods and not for functions.

Methods with pointer receiver are very useful to get a “Java” like behavior where the method is actually modifying on the value to which the receiver points and not on a copy of it.

答案4

得分: 0

Go方法与Go函数类似,只有一个区别,即方法中包含一个接收器参数。通过接收器参数的帮助,方法可以访问接收器的属性。在这里,接收器可以是结构体类型或非结构体类型。

func (接收器名称 类型) 方法名称(参数列表)(返回类型){
    // 代码
}
英文:

Go methods are similar to Go function with one difference, i.e, the method contains a receiver argument in it. With the help of the receiver argument, the method can access the properties of the receiver. Here, the receiver can be of struct type or non-struct type.

func(reciver_name Type) method_name(parameter_list)(return_type){
    // Code
}

答案5

得分: 0

上面的答案对我来说很好。除此之外,我还想补充一点。

Function是从包中调用的东西。而method也是一个函数,但是是从特定类型的值中调用的。而values是函数的返回值。

例如:
1)rightNow := time.Now()

time --> 包,Now() --> 函数,因为它是由一个包调用的,rightNow是从Now()函数返回的type为time.Time的value

2)year := rightNow.Year()

rightNow --> 值,Year() --> function,但是由于它是由某个typevalue(这里是time.Time)调用的,因此它被称为Method。为了方便识别,方法具有与其调用的相同类型的接收器。

英文:

Above answer seems good to me. Along with that I would also like to add on it.

Function is something which is invoked from package. Whereas method is also a function but invoked from particular type values. And values is the return of functions.

For example:

  1. rightNow := time.Now()

time --> package, Now() --> function because invoked by a package, rightNow is the value of type time.Time returned from Now() function.

  1. year := rightNow.Year()

rightNow --> value, Year() --> function but since it is invoked by a value of some type(here time.Time), therefore it is called a Method. For easily identication Method has a reciever of that same type from which it is invoked.

huangapple
  • 本文由 发表于 2011年11月25日 07:44:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/8263546.html
匿名

发表评论

匿名网友

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

确定