我正在尝试开始使用Go,documentation非常好。我在文档中没有找到的是函数和方法之间的区别。
据我所知,目前:函数是“全局的”,这意味着我不必导入包来使用函数,它们总是在那里。方法绑定到包。这是对的吗?
答案 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”的行为非常有用,其中该方法实际上修改了接收者指向的值而不是其副本。