Go中的函数和方法有啥区别?
Posted
技术标签:
【中文标题】Go中的函数和方法有啥区别?【英文标题】:Whats the difference of functions and methods in Go?Go中的函数和方法有什么区别? 【发布时间】:2012-01-06 00:08:12 【问题描述】:我正在尝试开始使用 Go,documentation 非常好。我在文档中没有找到的是函数和方法之间的区别。
据我目前的理解:函数是“全局的”,这意味着我不必导入包来使用函数,它们总是存在的。方法绑定到包。这是正确的吗?
【问题讨论】:
术语“方法”和“函数”只是历史惯例。简单的语言暗示“如何”与“什么”,事实并非如此,因此令人困惑。我们可能认为“函数”是数学的,但事实并非如此,因此令人困惑。事实上,“方法”只是从面向对象语言中采用的与特定类型相关联的,而“函数”是从函数是独立的过程语言中采用的。我想你可以在 go 中看到那些简单的解释:在类型上调用方法,而不是函数。 【参考方案1】:据我目前的理解:函数是“全局的”,这意味着我不必导入包来使用函数,它们总是存在的。方法绑定到包。这是正确的吗?
不,这是不正确的。 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)
【讨论】:
我不会说“Go 不是 OOP 语言”。 Go 恕我直言,它非常喜欢组合而不是继承,它为前者提供了额外的语法糖,并完全摆脱了后者。 我不确定。恕我直言,OOP 范式的一部分也是子类化 + 类型层次结构。这在 Go 中是不可能的(幸运的是!)。当然,Go 提供了其他方法(即嵌入)来解决类似问题,但它们不是 1:1 的替代品。但是让我们停止使用术语-bikeshedding :D 谢谢,我终于明白了!一个缺失的部分是,方法总是与类型结合使用。 @tux21b 谢谢你的例子。一个问题,你的方法包含一个invalid operation: a + b (mismatched types MyInteger and int)
。为了使其工作,您需要将a
转换为int
或将b
转换为MyInteger
。例如:return int(a) + b
或 return a + MyInteger(b)
。在第二种情况下,您需要将方法签名中的返回值类型更改为MyInteger
而不是int
。 playground
我要指出这句话说:“Go 不是经典意义上的 OOP 语言”,并不是说它不是 OOP 语言【参考方案2】:
Tux 的答案很棒,但我想通过使用 Go 的方法和 struct
s 来扩充它(因为这是我经常使用它的地方)。因此,让我们假设您想要构建一些东西来计算三角形的各种方法。你从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 中,人们可能已经创建了一个类,然后添加了方法。我们可以将我们的结构体视为一种带有字段的类,现在我们添加方法:
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。
请注意,它看起来真的很像对象的方法。
【讨论】:
【参考方案3】:这里有详细解释-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”的行为非常有用,其中该方法实际上修改的是接收器指向的值,而不是它的副本。
【讨论】:
只是想知道,这会破坏目的,因为关于不变性的整个论点不是修改值?以上是关于Go中的函数和方法有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
在 C# 中,类中的析构函数和 Finalize 方法有啥区别?