Go语言基础语法
一、函数
在Go语言中,函数是第一类对象,我们可以将函数保持到变量中。函数主要有具名和匿名之分,包级函数一般都是具名函数,具名函数是匿名函数的一种特例,当匿名函数引用了外部作用域中的变量时就成了闭包函数,闭包函数是函数式编程语言的核心。
举例代码如下:
- 具名函数:就和c语言中的普通函数意义相同,具有函数名、返回值以及函数参数的函数。
func Add(a, b int) int {
return a+b
}
- 匿名函数:指不需要定义函数名的一种函数实现方式,它由一个不带函数名的函数声明和函数体组成。
var Add = func(a, b int) int {
return a+b
}
解释几个名词如下:
-
闭包函数:返回为函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
-
一级对象:支持闭包的多数语言都将函数作为第一级对象,就是说函数可以存储到变量中作为参数传递给其他函数,最重要的是能够被函数动态创建和返回。
-
包:go的每一个文件都是属于一个包的,也就是说go是以包的形式来管理文件和项目目录结构的。
1.1 函数声明
Go语言函数定义格式如下:
func fuction_name([parameter list])[return types]{
函数体
}
| 解析 | |
|---|---|
| func | 函数由func开始声明 |
| function_name | 函数名称 |
| parameter list | 参数列表 |
| return_types | 返回类型 |
| 函数体 | 函数定义的代码集合 |
1.2 函数返回值
举例代码如下
func Find(m map[int]int, key int)(value int, ok bool) {
value,ok = m[key]
return
}
如果返回值命名了,可以通过名字来修改返回值,也可以通过deferi语句在returni语句之后修改返回值, 举例代码如下:
func mian() {
for i := 0 ; i<3; i++ {
defer func() { println(i) }
}
}
// 该函数最终的输出为:
// 3
// 3
// 3
以上代码中如果没有defer其实返回值就是0,1,2,但defer语句会在函数return,之后才会执行,也就是或只有以上函数在执行结束return之后才会执行defer语句,而该函数return时的i值将会达到3,所以最终的defer语句执行println的输出都是3。
defer语句延迟执行的其实是一个匿名函数,因为这个匿名函数捕获了外部函数的局部变量v,这种函数我们一般叫闭包。闭包对捕获的外部变量并不是传值方式访问,而是以引用的方式访问。
这种方式往往会带来一些问题,修复方法为在每一轮迭代中都为defer和函数提供一个独有的变量,修改代码如下:
func main() {
for i := 0; i < 3; i++ {
i := i // 定义一个循环体内局部变量i
defer func(){ println(i) } ()
}
}
func main() {
for i := 0; i < 3; i++ {
// 通过函数传入i
// defer 语句会马上对调用参数求值
// 不再捕获,而是直接传值
defer func(i int){ println(i) } (i)
}
}
二、 条件语句
| 语句 | 描述 |
|---|---|
| if语句 | if语句由一个布尔表达式后紧跟一个或多个语句组成 |
| if...else语句 | if语句后可以使用可选的else语句,else语句中的表达式在布尔表达式为false时执行 |
| switch语句 | switch语句用于不同条件执行不同动作 |
| select语句 | select语句类似于switch语句,但是select会随机执行一个可运行的case。如果没有case可运行,他将阻塞,直到有case可运行 |
if语句
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
}
if...else语句
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
switch语句
其中的变量v可以是任何类型,val1和val2可以是同类型的任意值,类型不局限为常量或者整数,或者最终结果为相同类型的表达
式。
switch v {
case val1:
...
case val2:
...
default:
...
}
select语句
select是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。它将会
随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的.
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}
三、 循环语句
3.1 循环处理语句
go语言中只有for循环一种,有三种形式
| 语法 | |
|---|---|
| 和c语言中的for相同 | for init; condition;post {} |
| 和c语言中的while相同 | for condition {} |
| 和c语言中的for( ; ; )相同 | for {} |
除此以外,for循环还可以直接使用range对slice、map、数组以及字符串等进行迭代循环,格式如下:
for key, value := range oldmap {
newmap[key] = value
}
3.2 循环控制语句
| 控制语句 | 详解 |
|---|---|
| break | 中断跳出循环或者switch语句 |
| continue | 跳过当前循环的剩余语句,然后继续下一轮循环 |
| goto | 将控制转移到被标记的语句 |
- break
a := 0
for a<5 {
fmt.Printf("%d\n", a)
a++
if a==2 {
break;
}
}
/* output
0
1
2
*/
- continue
// 不使用标记
fmt.Println("---- continue ---- ")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue
}
}
/* output
i: 1
i2: 11
i2: 12
i2: 13
i: 2
i2: 11
i2: 12
i2: 13
i: 3
i2: 11
i2: 12
i2: 13
*/
// 使用标记
fmt.Println("---- continue label ----")
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
continue re
}
}
/* output
i: 1
i2: 11
i: 2
i2: 11
i: 3
i2: 11
*/
- goto
var a int = 0
LOOP: for a<5 {
if a == 2 {
a = a+1
goto LOOP
}
fmt.Printf("%d\n", a)
a++
}
/*
output:
0
1
2
3
4
*/