Go 语言入门指南(二) | 青训营
这篇博客继续对go的基础语法进行整理。主要包括:函数、结构体。
一. go 的函数
函数其实除了参数、返回值的位置有些不同外,其实和其他语言的函数没什么区别,都是一样,注意函数名、参数列表和返回值即可。其次,go的函数传递的都是值,在函数内的修改并不影响函数外。
另外就是,理解函数也是一个类型,函数类型。例:func(int, string) int表示参数是int和string类型、返回值是int类型的函数。
函数参数、返回值也都可以是函数类型。
第二是理解defer:
defer 修饰的函数调用会在函数即将返回时最后执行,==但是传递的参数已经传递了,只是保存起来了==。一般用在释放资源(如文件描述符)的语句,当函数退出时最后释放资源。多个时最先defer修饰的最后执行(栈)。
go底层函数return时不是原子的,会分为两步:一是给返回值赋值;二是RET(返回),而defer语句在两者之间,即返回值赋值之后执行defer语句,最后是RET。
当defer修饰的函数参数有嵌套的函数调用时会先执行嵌套的函数调用,得到具体的值保存起来,最后只执行一层函数调用。
最后是闭包的理解,闭包一般都是通过匿名函数实现的。这个理解起来确实有点抽象!看两个示例:
func f1(x int) func(int) int{
return func(y int) int{
// 这个x就是外部的变量
return x + y
}
}
func main(){
// x : 100
ret := f1(100)
// y : 200
ret2 := ret(200) // ret2: 300 int类型
}
func f1(f func()){
// ...
f() // 闭包后f1里调用的这个f就是f2
// ...
}
func f2(x, y int){
// ...
}
// f3参数是f2的那一套,返回值是f1的参数
func f3(f func(int,int), x,y int) func(){
return func(){
// 这里就相当于调用了传入的函数
f(x, y)
}
}
func main(){
// 想要 f1(f2), 但是类型不匹配。借助f3 闭包,像一个跳板一样。
// f3的返回值(匿名函数)刚好是f1的参数,而f3的参数是f2的。这样把原来需要传递两个int类型的参数包装成了一个匿名函数传给f1
f1(f3(f2, 100, 200))
f3(f2, 100, 200)() // 这样就相当于调用f2
// 一般这样用
ret := f3(f2, 100, 200)
f1(ret)
}
在第二个示例中,想要 f1(f2), 但是类型不匹配。就借助f3 闭包,像一个跳板一样。
下面是一些常用的内置函数:
close:关闭channel
len:求长度
new:分配内存,用于值类型,如内置类型和数组、结构体。返回指针
make:分配内存,用于引用类型,如切片、map、channel。返回类型本身
append:追加元素到数组、切片中
panic:处理错误,直接报错退出程序
recover:处理错误,尝试恢复
二. 结构体
go的结构体也很简单,看下面的实例:
// 在函数外声明
type person struct{
name string
age int
hobby []string
}
func main(){
// 初始化方法1
var p person
p.name = "sfsda"
// 初始化方法2
// new 返回结构体的指针, go中访问结构体变量没有 ->
// 即使是结构体指针,也可以用 .
var p1 = new(person)
p1.name = " sdfsdf"
// 初始化方法3
var p3 = &person{ // &可以省略,加上表示p3是结构体指针
name: "fsdaf",
age: 12,
}
p33 := &person{
// ...
}
// 初始化方法4
var p3 = &person{
"fsdaf",
12,
[]string{"asfk", "safkls"},
}
}
需要注意的是:结构体函数传参一般==传指针==,不然拷贝数据量太大!!性能低(go中函数传参都是传值)。
这一篇文章就介绍到这里吧!下一篇是入门的最后一篇,总结一下接口和文件操作。