1.Go语言条件语句
和C++一样,Go语言提供了几种条件判断语句:if语句,if...else语句,if嵌套语句,switch语句。上述语句功能和C++相同,此外还提供了新的select语句。
if语句
Go 编程语言中 if 语句的语法如下:
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
}
写法和C++基本相同,特别要注意花括号不能单独成行。
if...else语句
Go 编程语言中 if...else 语句的语法如下:
if 布尔表达式 {
/* 在布尔表达式为 true 时执行 */
} else {
/* 在布尔表达式为 false 时执行 */
}
同样要注意花括号~
if嵌套语句
Go 编程语言中 if嵌套语句的语法如下:
if 布尔表达式 1 {
/* 在布尔表达式 1 为 true 时执行 */
if 布尔表达式 2 {
/* 在布尔表达式 2 为 true 时执行 */
}
}
switch语句
Go 编程语言中 switch 语句的语法如下:
switch var1 {
case val1:
...
case val2:
...
default:
...
}
需要注意的是,switch 语句执行的过程从上至下,直到找到匹配项,匹配项后面也不需要再加 break,因为switch 默认情况下 case 最后自带 break 语句,匹配成功后就不会执行其他 case,这一点与C++不同,如果我们需要执行后面的 case,可以使用 fallthrough 。
示例:
package main
import "fmt"
func main() {
/* 定义局部变量 */
var grade string = "B"
var marks int = 90
switch marks {
case 90: grade = "A"
case 80: grade = "B"
case 50,60,70 : grade = "C"
default: grade = "D"
}
switch {
case grade == "A" :
fmt.Printf("优秀!\n" )
case grade == "B", grade == "C" :
fmt.Printf("良好\n" )
case grade == "D" :
fmt.Printf("及格\n" )
case grade == "F":
fmt.Printf("不及格\n" )
default:
fmt.Printf("差\n" );
}
fmt.Printf("你的等级是 %s\n", grade );
}
以上代码执行结果为:
优秀! 你的等级是 A
switch 语句还可以被用于 type-switch 来判断某个 interface 变量中实际存储的变量类型。这是C++的switch没有的功能。
Type Switch 语法格式如下:
switch x.(type){
case type:
statement(s);
case type:
statement(s);
/* 你可以定义任意个数的case */
default: /* 可选 */
statement(s);
}
示例:
package main
import "fmt"
func main() {
var x interface{}
switch i := x.(type) {
case nil:
fmt.Printf(" x 的类型 :%T",i)
case int:
fmt.Printf("x 是 int 型")
case float64:
fmt.Printf("x 是 float64 型")
case func(int) float64:
fmt.Printf("x 是 func(int) 型")
case bool, string:
fmt.Printf("x 是 bool 或 string 型" )
default:
fmt.Printf("未知型")
}
}
以上代码执行结果为:
x 的类型 :<nil>
使用 fallthrough 会强制执行后面的 case 语句,fallthrough 不会判断下一条 case 的表达式结果是否为 true。
package main
import "fmt"
func main() {
switch {
case false:
fmt.Println("1、case 条件语句为 false")
fallthrough
case true:
fmt.Println("2、case 条件语句为 true")
fallthrough
case false:
fmt.Println("3、case 条件语句为 false")
fallthrough
case true:
fmt.Println("4、case 条件语句为 true")
case false:
fmt.Println("5、case 条件语句为 false")
fallthrough
default:
fmt.Println("6、默认 case")
}
}
以上代码执行结果为:
2、case 条件语句为 true 3、case 条件语句为 false 4、case 条件语句为 true
从以上代码输出的结果可以看出:switch 从第一个判断表达式为 true 的 case 开始执行,如果 case 带有 fallthrough,程序会继续执行下一条 case,且它不会去判断下一个 case 的表达式是否为 true。
select语句
Go 编程语言中 select 语句的语法如下:
select {
case communication clause :
statement(s);
case communication clause :
statement(s);
/* 你可以定义任意数量的 case */
default : /* 可选 */
statement(s);
}
以下描述了 select 语句的语法:
- 每个 case 都必须是一个通信
- 所有 channel 表达式都会被求值
- 所有被发送的表达式都会被求值
- 如果任意某个通信可以进行,它就执行,其他被忽略。
- 如果有多个 case 都可以运行,Select 会随机公平地选出一个执行。其他不会执行。
否则:- 如果有 default 子句,则执行该语句。
- 如果没有 default 子句,select 将阻塞,直到某个通信可以运行;Go 不会重新对 channel 或值进行求值。
select 语句应用演示:
package main
import "fmt"
func main() {
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
以上代码执行结果为:
no communication
这段代码涉及到Go并发的知识,这里还未学到,所以暂时先将select理解成一个用于判断通信的特殊switch语句,执行的过程如上语法所示。
2.Go语言循环语句
Go 语言的 For 循环有 3 种形式,只有其中的一种使用分号。
和 C++ 的 for 一样:
for init; condition; post { }
和 C++ 的 while 一样:
for condition { }
和 C++ 的 for(;;) 一样:
for { }
- init: 一般为赋值表达式,给控制变量赋初值;
- condition: 关系表达式或逻辑表达式,循环控制条件;
- post: 一般为赋值表达式,给控制变量增量或减量。
for 循环的 range 格式可以对 slice、map、数组、字符串等进行迭代循环。格式如下:
for key, value := range oldMap {
newMap[key] = value
}
以上代码中的 key 和 value 是可以省略的。
如果只想读取 key,格式如下:
for key := range oldMap
//或者:
for key, _ := range oldMap
如果只想读取 value,格式如下:
for _, value := range oldMap
示例:
package main
import "fmt"
func main() {
map1 := make(map[int]float32)
map1[1] = 1.0
map1[2] = 2.0
map1[3] = 3.0
map1[4] = 4.0
// 读取 key 和 value
for key, value := range map1 {
fmt.Printf("key is: %d - value is: %f\n", key, value)
}
// 读取 key
for key := range map1 {
fmt.Printf("key is: %d\n", key)
}
// 读取 value
for _, value := range map1 {
fmt.Printf("value is: %f\n", value)
}
}
运行输出结果为:
key is: 4 - value is: 4.000000 key is: 1 - value is: 1.000000 key is: 2 - value is: 2.000000 key is: 3 - value is: 3.000000 key is: 1 key is: 2 key is: 3 key is: 4 value is: 1.000000 value is: 2.000000 value is: 3.000000 value is: 4.000000
for循环的range格式其实就是对一个容器进行遍历,在循环体中进行操作,其具体用法在Go语言range一章再具体说明,这里主要先清楚for语句的语法格式。
可以看到同样是for语句的情况下Go语言几乎只是比C++少了两个圆括号(),写法基本相同,赋值语句与循环控制条件也是由分号隔开。对于C++的while语句,在Go语言中还是使用for来表示,但也基本只有这个区别。
循环嵌套语句就不记录了,写法跟if嵌套是一个道理的。Go的循环控制语句也是break、continue、goto三条,这三个语句都可以使用标记来跳转到想要执行的语句,以break为例:
package main
import "fmt"
func main() {
// 不使用标记
fmt.Println("---- break ----")
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break
}
}
// 使用标记
fmt.Println("---- break label ----")
re:
for i := 1; i <= 3; i++ {
fmt.Printf("i: %d\n", i)
for i2 := 11; i2 <= 13; i2++ {
fmt.Printf("i2: %d\n", i2)
break re
}
}
}
执行结果为:
---- break ---- i: 1 i2: 11 i: 2 i2: 11 i: 3 i2: 11 ---- break label ---- i: 1 i2: 11
3.Go语言函数
函数定义
Go 语言函数定义格式如下:
func function_name( [parameter list] ) [return_types] {
函数体
}
函数定义解析:
- func:函数由 func 开始声明(不同于C++从返回值类型开始声明)
- function_name:函数名称,参数列表和返回值类型构成了函数签名。
- parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,也就是说函数也可以不包含参数。
- return_types:返回类型,函数返回一列值。return_types 是该列值的数据类型。有些功能不需要返回值,这种情况下 return_types 不是必须的。(返回值类型写在参数列表之后)
- 函数体:函数定义的代码集合。
以下实例为 max() 函数的代码,该函数传入两个整型参数 num1 和 num2,并返回这两个参数的最大值:
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int
if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}
函数调用方法和C++相同,不作记录,这里提一下返回多个值的功能。
Go 函数可以返回多个值,例如:
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("Google", "Runoob")
fmt.Println(a, b)
}
执行结果为:
Runoob Google
函数返回多个值是C++没有的功能,C++的函数只有一个返回值。
函数参数的传递也一样有值传递和引用传递两种,效果同C++,这里不作记录。
Go语言变量作用域规则与C++相同,不作记录。
4.Go语言数组
声明数组
Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:
var variable_name [SIZE] variable_type
以上为一维数组的定义方式。例如以下定义了数组 balance 长度为 10 类型为 float32:
var balance [10] float32
初始化数组
以下演示了数组初始化:
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
//或者
balance := [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
如果数组长度不确定,可以使用 ... 代替数组的长度,编译器会根据元素个数自行推断数组的长度:
var balance = [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
或
balance := [...]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
如果设置了数组的长度,我们还可以通过指定下标来初始化元素:
// 将索引为 1 和 3 的元素初始化
balance := [5]float32{1:2.0,3:7.0}
这个指定下标的初始化功能是C++没有的,C++中要初始化数组部分元素只能在声明时给数组前几位赋值,并不能像这样指定下标赋值。
访问数组元素
数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。例如:
var salary float32 = balance[9]
多维数组和向函数传递数组与C++相同,不作记录。
5.Go语言指针
指针声明
var var_name *var-type
var-type 为指针类型,var_name 为指针变量名,* 号用于指定变量是作为一个指针。以下是有效的指针声明:
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮点型 */
在指针类型前面加上 * 号(前缀)来获取指针所指向的内容(同C++)。
package main
import "fmt"
func main() {
var a int= 20 /* 声明实际变量 */
var ip *int /* 声明指针变量 */
ip = &a /* 指针变量的存储地址 */
fmt.Printf("a 变量的地址是: %x\n", &a )
/* 指针变量的存储地址 */
fmt.Printf("ip 变量储存的指针地址: %x\n", ip )
/* 使用指针访问值 */
fmt.Printf("*ip 变量的值: %d\n", *ip )
}
执行输出结果为:
a 变量的地址是: 20818a220
ip 变量储存的指针地址: 20818a220
*ip 变量的值: 20
Go 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
一个指针变量通常缩写为 ptr。
package main
import "fmt"
func main() {
var ptr *int
fmt.Printf("ptr 的值为 : %x\n", ptr )
}
输出结果为:
ptr 的值为 : 0
空指针判断:
if(ptr != nil) /* ptr 不是空指针 */
if(ptr == nil) /* ptr 是空指针 */
其实Go语言的指针除了写法和C++有区别以外就没什么不同点了,像指针的使用、指针数组、多级指针、指针作为函数参数等操作和C++是一样的,因此不作记录。
6.总结
第二章学习记录包含了条件语句、循环语句、函数、数组、指针,每个部分都和C++大致相同,不过也多了一些C++没有的功能,比如select语句、for循环range格式、函数返回多个值、初始化数组指定下标元素等。