函数、包、错误处理
函数
概念和Java的一样。但是不同的点在于,go放入函数可以返回多个参数,这个是其他语言没有的;例如,求两个数的和和差
1 | func main() { |
如果希望不使用或者忽略变量,那么可以使用一个下划线来表示忽略,返回值只要写类型。使用return返回数据
如果你要编写一个可执行文件,编写一个可以运行看一下运行结果的话,那么那一个文件的包必须是main,函数必须是main()
函数的递归:求1到n的和
1 | func main() { |
函数的命名也是首字母大写代表public
函数使用细节讨论
函数不可以修改函数外面的值,如果要修改可以使用指针修改数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25func main() {
a:=1
test(&a)
fmt.Println(a)
}
func test(a *int){//传入指针修改数据
b:=2
*a=b;
}
//交换两个参数的值
func main() {
a:=1
b:=2
fmt.Println("交换前 \t",a,"\t",b)
exchange(&a,&b)
fmt.Println("交换后 \t",a,"\t",b)
}
func exchange(a *int,b *int){
t:=0
t=*a
*a=*b
*b=t
}go函数不支持函数的重载
在go中函数也是一种数据类型,可以赋值给一个变量,通过该变量实现对函数的引用;
1
2
3
4
5
6
7
8
9func main() {
a:=2
b:=test(a)
fmt.Printf("%T \n",test) //func(int) int
fmt.Println(b)//2
}
func test(a int)(int){
return a
}func括号里面的是参数类型
1
2
3
4
5
6
7
8func main() {
a:=test
fmt.Println(a())//调用函数
fmt.Printf("%T",a) //类型是func() string
}
func test() string {
return "通过变量应用函数"
}感觉是实际上是给函数取一个别名
函数可以做另一个函数的形参使用
1
2
3
4
5
6
7
8
9func main() {
fmt.Println(test(sum,2,3))
}
func test(fun func(int, int) int, a int, b int) int {
return fun(a,b)
}
func sum(a int, b int) int {
return a + b
}引用函数的时候,类型就是使用%T输出的那个类型,不要忘记写函数返回值类型
为了简便数据类型的定义,可以自己定义数据类型,函数也可以
type 名字 数据类型
数据类型取别名
1
2
3
4
5
6type myint int
func main() {
var a myint = 3 //在原本写类型的地方写上我们的别名
fmt.Println(a)
}函数类型取别名
1
2
3
4
5
6
7
8
9
10
11
12
13import "fmt"
type myfun func(int, int) int
func main() {
fmt.Println(test(sum,1,2))
}
func test(fun myfun, a int, b int) int {
return fun(a, b)//在表名函数类型的地方写上我们对函数类型取的别名
}
func sum(a int, b int) int {
return a + b
}取别名只是在使用函数作为参数的时候,相同的函数类型才可以替换
给函数返回值取别名
给返回值取别名以后,我们的不用写return 别名,直接写上返回值的表达式,他会自动返回
1
2
3
4func sum(a int, b int) (myint int) {
myint=a+b
return
}但是值的注意的是,我们虽然给函数的返回值去了别名,但是我们输出他的函数类型的时候,依然是原样
1
2fmt.Printf("%T",sum)
//结果 func(int, int) int函数支持可变长参数,使用args… 数据类型(int string float32 float64…) 表示,如果还有其他的参数,那么可变长参数要放在最后至于原因嘛,据我推测,如果你的可变长参数在前,你的后一个参数和你的可变长参数类型一样,那么系统就不知道,谁是谁
1
2
3
4
5
6
7
8
9
10func main() {
fmt.Println(test(1,1,2,3,4,5,6,7,8,9))
}
func test(a int,args... int) int{
sum:=0
for i:=0;i<len(args);i++{
sum+=args[i]
}
return sum
}- 说明args是切片,通过args[index]可以访问到各个值
init 初始化函数
初始化函数最主要的作用就是,完成一些 初始化工作,比如给变量赋值等,如果有引用的包,那么引用的包的初始化函数就比这个函数先
1 | //引用的包 |
匿名函数
就是只使用一次的函数,不用给名字,和java概念一样,像下面这个方式引用,那么他只能被调用一次
1 | func main() { |
参数写在最后面,参数类型和函数返回值类型放在前面,使用和前面的一般函数一样,当我们把这个函数使用一个变量来接受,我们就可以使用这个函数来调用这个函数,实际上也算是给这个匿名函数取名
1 | a:= func(a int, b int) (sum int,sub int) { |
我们如果想要在函数的内部定义函数,不能直接定义,需要使用匿名函数
1 | func main() { |
当然,如果我们把这个匿名函数赋值给一个全局变量那么他就是全局匿名函数
1 | var( |
这个时候,有人要问了,这个有什么用啊,实际上我也不知道,以后看源码就明白了,现在先记着有这么个概念
闭包

1 | func main() { |
实际上,闭包就是函数的实现,用属性和操作(匿名函数)操作数据,实际上函数的参数就是匿名函数,匿名函数的返回值就是这个函数的返回值 而我们的函数里面的变量就相当于我们的属性,可以操作,并且如果一直是一个对象的话,那么他的属性就不会消失,就是同一个
==再次强调,我们的函数引用带()表示返回值,不带括号表示那个变量就是函数本身==
defer
当我们不想立马执行某一个语句,只想等所有的语句都结束了在执行,我们就可以使用defer这个关键字,他会把我们的带有defer的语句放到栈(先进后出)中,在所有的函数执行完了后,再返回俩执行这些压入栈的语句,例如:
1 | func main() { |
值的我们关注的是,我们的语句虽然是后来执行但是,我们的值也在那个时候被拷贝到栈中,所以数据会被携带。一般可以用于资源的关闭,例如数据库操作完毕后,使用connection.close(),在Java的时候,我们需要使用try catch finally,在finally语句里面执行关闭操作,但是在go中,只要函数执行完了就可以关闭,不用担心在什么时候能关闭资源,或者忘记关闭资源
常见的strings函数
1 | str1 := "hello world" |
结果:
1 | false |
常见的时间日期处理函数
1 | //获得当前时间 |
内置函数
就是可以直接使用的函数,例如前面用过的 len()
len(),用来求某些类型数据的长度
new(数据类型),用来声明变量,声明后就是指针,这个b存的是地址,那个地址才是真正的数据
1
2b:=new(int)
fmt.Println(*b)make:用来分配内存,后面在解释
错误处理
这里介绍的就是关于go的异常捕获
由于为了简洁,所以go语言的设计者,没有使用Java里面的捕获异常机制,而是使用 **==defer+recover==**处理错误
1 | func main() { |
运行结果:
1 | 程序运行过程中,发现错误 |
这样的好处是,程序不会因为发送错误就退出,可以一直执行下去 和Java一样,我们自定义错误,让程序遇见我们自定义的错误的时候,也会停止运行而退出
自定义错误
1 | func test05() { |
包
访问其他包的函数使用 包名+函数名
如果包名太长,可以使用别名,但是一旦使用别名的话,原来的包名就不可以使用了;
1
2
3
4
5
6
7
8
9package main
import (
demo "../Demo2"
)
func main() {
demo.Test()
}import 引入的包的时候,位置是相对路径。相当于是一个类,引用里面的静态方法;



