一、函数
1、函数的基本语法

2、函数的调用过程

- 上面的堆和栈都是逻辑空间,从上图可以得知:
- (1)在调用一个函数时,会给该函数分配一个新的空间,编译器会通过自身的处理让这个新的空间和其他栈的空间区分开来
- (2)每个函数对应的栈中,数据空间是独立的,不会混淆
- (3)当一个函数调用完毕后,编译器会自动销毁这个函数对应的栈空间。
3、函数的递归调用
在数据结构中,递归是一个重要的知识。
一个函数在函数体内又调用了本身,我们称为递归调用。
1)、示例一及分析图:
输出结果:n=2 n=2 n=3

2)、示例二及分析图:
输出结果:n=2


3)、递归调用的总结:
- 函数递归需要遵守的重要原则:
- 1、执行一个函数时,就会创建一个新的受保护的独立空间(新函数栈)
- 2、函数的局部变量是独立的,不会相互影响
- 3、递归必须向退出递归的条件逼近,否则就是无限递归了
- 4、当一个函数执行完成或者遇到return,就会返回。遵守:谁调用就将结果返回给谁。同时当函数执行完毕或者返回后,该函数本身也会被系统销毁。
4、函数的使用注意事项
- (5)基本类型和数组默认都是值传递的,即进行值拷贝。在函数内修改,不会影响到原来的值。在Java里面,数组是引用传递。


- (6)如果形参是以值传递的方式的引用类型,我们想要修改原值,怎么操作?这时需要把该值的地址传进去&,函数内以指针的方式操作变量。从效果上看类似引用传递。

注意:此时test2里的n1和main里的n1有不同的地址。因为是存在于不同的栈空间的。调用函数时,会为函数新开辟一个栈空间。类似于下图,n1和n1存在于不同的栈空间:

- (7)Go函数不支持函数重载(它是以其他方式实现的)
5、init函数
当全局变量、init函数、main函数同时存在,且引入的utils也存在时,执行流程是什么呢?

6、匿名函数
匿名函数可以定义在函数内部,如main函数内部。

7、闭包
定义:闭包就是一个函数与其相关的引用环境组合的一个整体
简单来说,就是:闭包=return 匿名函数+引用的变量(变量只会初始化一次) 组合的整体
案例一:

案例二:


8、时间和日期函数 import time


9、随机数math.rand
10、内置函数
内置函数,也叫内建函数。就是程序本身定义好的一些函数,我们可以拿来直接使用,不需要导入包
查看文档 buildin模块
常用的内置函数:
- 1、len函数,用来求长度,比如string、数组、切片、map、channel
func len(v Type) int:内建函数len返回 v 的长度,取决于具体类型:...
- 2、new函数,用来分配内存,主要用来分配值类型,比如int,float32...返回结果是指针类型

上面代码对应的内存分析图:

- 3、make函数,用来分配内存,主要用来分配引用类型,比如chan,map,slice...
二、包
1、包的使用注意事项
- (1)在给一个文件打包时,该包对应一个文件夹。比如这里的utils文件夹对应的包名是utils
文件的包名和文件所在的文件夹名一致,一般为小写字母。
如果文件的包名和文件所在的文件夹名不一致,可以吗?
- (3)函数名或变量名大写,才能被其他包访问到,类似于其他语言中的public
- (4)访问其他包的函数或变量,其语法是:包名.函数名() 包名.变量名
- (5)如果包名比较长,Go支持给包取别名,如main3.go
调用:包的别名.函数名() 包的别名.变量名 // 注意:取别名后,原来的包名就不能用了
- (6)同一包下,不能有相同的函数名和全局变量名
- (7)如果需要编译成一个可执行文件,需要将这个包名声明为main,即package main.语法规范就这样
如果你写一个库,包名可以自定义
三、错误处理机制
- (1)Go语言追求简洁优雅,所以不支持传统的try...catch...finally这种处理
- (2)Go中引入的处理方式为:defer, panic, recover
- (3)使用场景:Go中可以手动抛出一个panic的异常,然后在defer中通过recover捕获这个异常,后续流程正常处理。

2、自定义错误
- Go支持自定义错误,使用errors.New和panic内置函数
- (1)errors.New("错误说明")会返回一个error类型的值,表示一个错误。import errors
- (2)panic内置函数,接收一个interface{}类型的值(可以是任何值)作为参数。可以接收error类型的变量,输出错误信息,并退出程序



四、函数参数传递方式(底层原理图)
1、两种方式:值传递和引用传递
值类型参数默认就是值传递,引用类型参数默认就是引用传递。
2、区别与联系
不管是值传递还是引用传递,传递给函数的都是变量的副本。不同的是,值传递的是值的拷贝,引用传递是地址的拷贝。一般来说,地址拷贝效率高,因为数据量小。而值传递取决于拷贝的数据大小,数据越大,效率越低。
3、使用特点,和Java对比



五、变量


注意:
- 1、相同名称的两个变量可以同时存在不同的作用域中,理解成不同的两个变量就行了。
- 2、:= 不能定义全局变量
如:age := 12 // 定义为全局变量报错。因为:等价于 var age int 和 age = 12。 age = 12是赋值语句,赋值语句不能写在函数体外
六、常量
用const定义