英文:
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 struct
s (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 > 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
}
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 > 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
}
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("sample")
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("sample")
add(&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("sample")
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
,但是由于它是由某个type
的value
(这里是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:
rightNow := time.Now()
time
--> package, Now()
--> function because invoked by a package, rightNow
is the value
of type
time.Time returned from Now() function.
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论