go语言初识——函数、方法、defer的使用
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
函数
为完成某一功能的程序指令(语句)的集合称为函数。
在Go语言中函数是第一类对象我们可以将函数保持到变量中。函数主要有具名和匿名之分包级函数一般都是具名函数具名函数是匿名函数的一种特例当匿名函数引用了外部作用域中的变量时就成了闭包函数闭包函数是函数式编程语言的核心。
格式
func fuction_name([parameter list])[return types]{
函数体
}
具名函数
和c语言中的普通函数意义相同具有函数名、返回值以及函数参数的函数。
func add(a, b int) int {
return a + b
}
匿名函数
指不需要定义函数名的一种函数实现方式它由一个不带函数名的函数声明和函数体组成。
var Add = func(a, b int) int {
return a + b
}
fmt.Println(Add(1, 2))
名词解释
闭包函数返回为函数对象不仅仅是一个函数对象在该函数外还包裹了一层作用域这使得该函数无论在何处调用优先使用自己外层包裹的作用域。
一级对象支持闭包的多数语言都将函数作为第一级对象就是说函数可以存储到变量中作为参数传递给其他函数最重要的是能够被函数动态创建和返回。
包go的每一个文件都是属于一个包的也就是说go是以包的形式来管理文件和项目目录结构的。
函数传参
Go语言中的函数可以有多个参数和多个返回值参数和返回值都是以传值的方式和被调用者交换数据。在语法上函数还支持可变数量的参数可变数量的参数必须是最后出现的参数可变数量的参数其实是一个切片类型的参数。
func main() {
var a = []int{1, 2, 3}
Print("name", "wht")
Print(a)
}
func Print(a ...interface{}) {
fmt.Println(a...)
}
//name wht
//[1 2 3]
函数返回值
不仅函数的参数可以有名字也可以给函数的返回值命名。
func swap(a, b int) (c, d int) {
c = b
d = a
return
}
func main() {
a, b := 1, 2
a, b = swap(a, b)
fmt.Println(a, b)
}
//2 1
defer
defer一般用于资源的释放和异常的捕捉, 作为Go语言的特性之一.
-
defer 语句会将其后面跟随的语句进行延迟处理. 意思就是说 跟在defer后面的语言 将会在程序进行最后的return之前再执行.
-
延迟函数的参数在defer语句出现时就已经确定了
-
在 defer 归属的函数即将返回时将延迟处理的语句按 defer 的逆序进行执行也就是说先被 defer 的语句最后被执行最后被 defer 的语句最先被执行(defer进行压栈和弹栈过程)。
func main() { a := 1 defer fmt.Println(a) a = 2 defer fmt.Println(a) a = 3 defer fmt.Println(a) } //3 2 1
-
延迟函数可能操作主函数的具名返回值
当定义defer的函数主函数有返回值返回值可能有名字具名返回值也可能没有名字匿名返回值延迟函数可能会影响返回值。
func deferFuncReturn() (result int) { i := 1 defer func() { result++ }() return i }
//实际会解析成以下操作 result = i result ++ return
函数返回过程关键字return不是一个原子操作实际上return只代表汇编指令ret即跳转程序执行。
比如 return i 实际上分两步执行即先将 i 值存入栈中作为返回值然后执行跳转而defer的执行时机正是在跳转前所以说defer执行时还是有机会操作返回值。
方法
方法一般是面向对象编程(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 {
// ...
}
但函数都是普通函数并不是面向对象的思想
go语言使用在函数名前传入类型指针即C++中this指针概念
func OpenFile(name string) (f *File, err error) {
// ...
}
func (f *File) CloseFile() error {
// ...
}
func (f *File) ReadFile(offset int64, data []byte) int {
// ...
}
从代码角度看虽然只是一个小的改动但是从编程哲学角度来看Go语言已经是进入面向对象语言的行列了。我们可以给任何自定义类型添加一个或多个方法。每种类型对应的方法必须和类型的定义在同一个包中因此是无法给int这类内置类型添加方法的因为方法的定义和类型的定义不在一个包中。对于给定的类型每个方法的名字必须是唯一的同时方法和函数一样也不支持重载。