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
中函数传参都是传值)。
这一篇文章就介绍到这里吧!下一篇是入门的最后一篇,总结一下接口和文件操作。