递归调用 Go语言中,函数还可以直接或间接地调用自己,也就是支持递归调用。Go语言函数的递归调用深度逻辑上没有限制,函数调用的栈是不会出现溢出错误的,因为Go语言运行时会根据需要动态地调整函数栈的大小。这部分的知识将会涉及goroutint和动态栈的相关知识,我们将会在之后的博文中向大家解释。
它的语法和c很相似,格式如下:
func recursion() { recursion() /* 函数调用自身 */ }
func main() { recursion() } 1 2 3 4 5 6 7 3.8 方法 方法一般是面向对象编程(OOP)的一个特性,在C++语言中方法对应一个类对象的成员函数,是关联到具体对象上的虚表中的。但是Go语言的方法却是关联到类型的,这样可以在编译阶段完成方法的静态绑定。一个面向对象的程序会用方法来表达其属性对应的操作,这样使用这个对象的用户就不需要直接去操作对象,而是借助方法来做这些事情。
实现C语言中的一组函数如下:
// 文件对象 type File struct { fd int }
// 打开文件 func OpenFile(name string) (f *File, err error) { // ... }
// 关闭文件 func CloseFile(f *File) error { // ... }
// 读文件数据 func ReadFile(f *File, offset int64, data []byte) int { // ... } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 以上的三个函数都是普通的函数,需要占用包级空间中的名字资源。不过CloseFile和ReadFile函数只是针对File类型对象的操作,这时候我们更希望这类函数和操作对象的类型紧密绑定在一起。
所以在go语言中我们修改如下:
// 关闭文件 func (f *File) CloseFile() error { // ... }
// 读文件数据 func (f *File) ReadFile(offset int64, data []byte) int { // ... } 1 2 3 4 5 6 7 8 9 将CloseFile和ReadFile函数的第一个参数移动到函数名的开头,这两个函数就成了File类型独有的方法了(而不是File对象方法)
从代码角度看虽然只是一个小的改动,但是从编程哲学角度来看,Go语言已经是进入面向对象语言的行列了。我们可以给任何自定义类型添加一个或多个方法。每种类型对应的方法必须和类型的定义在同一个包中,因此是无法给int这类内置类型添加方法的(因为方法的定义和类型的定义不在一个包中)。对于给定的类型,每个方法的名字必须是唯一的,同时方法和函数一样也不支持重载。