3.1go流程控制语句
算术运算符
注意: 自增 ++ ,自减 -- 只能是 A++, A-- 且是语句 也就是说不能放到等式,函数参数等地方。
go语言没有 ++A ,--A这种语句
关系运算符用于比较两个值,并返回一个布尔值(true 或 false)
逻辑运算符
位运算符
假定 A 为60,B 为13 。 A := 0b111100
B := 0b001101
&^
运算符(按位清除)
A&^ B:如果 B 的某一位是 1,则将 A 的对应位设置为 0;如果 B 的某一位是 0,则 A 的对应位保持不变。
A&^ B 结果为 48, 二进制为 110000
赋值运算符
其他运算符
Go 语言的取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址。
var a int
fmt.Printf("变量的值是: %v\t变量的地址: %[1]p\n", &a) //变量的地址: c000016098
a = 4
fmt.Printf("变量的值是: %vp\t变量的地址: %[1]p\n", &a)
Go语言中,指针是一个变量的内存地址。就是一个存储了其他数据项地址的数据项,或者说指针是一个存储了其他变量地址的变量。
-
Go 语言中的指针与 C/C++ 中的指针类似,但是 Go 语言中的指针不能进行指针运算,也不能进行指针类型转换。
-
指针是一种特殊的变量,它存储了一个变量的内存地址。通过指针,我们可以直接访问和修改变量的值,而不需要拷贝变量本身,这样可以提高程序的效率。指针在Go语言中有以下几个作用
-
传递变量的地址:指针可以作为函数参数,将变量的地址传递给函数,这样函数就可以直接修改变量的值。
-
动态分配内存:通过指针可以在运行时动态分配内存,这样程序就可以根据需要动态地创建和销毁变量。
-
访问复杂数据结构:指针可以用于访问复杂的数据结构,如链表、树等,通过指针可以方便地遍历和修改这些数据结构。
-
函数返回值:指针可以作为函数的返回值,这样函数就可以返回一个指向变量的指针,而不是变量本身,这样可以避免变量拷贝和内存分配的开销。
指针定义
var 指针变量名称 *指针类型
new()函数使用
开辟数据类型对应的内存空间,返回值为数据类型指针
var p *int
p = new(int) //int占用4字节,也就是开辟4字节的内存空间,给p指针变量
*p = 666
fmt.Println(p)
运算符优先级
if分支结构语句
// 可以在 if 表达式之前添加一个执行语句"score := 65;",再根据变量值进行判断:
if score := 65; score >= 90 {
fmt.Println("A")
} else if score > 75 {
fmt.Println("B")
} else {
fmt.Println("C")
}
// fmt.Println(score) 错误:score的作用域只在if里,出了if作用域就取不到这个score的变量了
if嵌套
题目:三只小猪比体重。
a=10 b=8 c=12 求那只小猪最重
switch case
-
Go语言switch语句常规写法
switch var1 {
case value1,value2:
// do something
case value3:
// do something
default:
// do something
}
-
switch后无变量,case后必须是判断符
a := 20
switch { // switch后没有待比较变量
case a > 0: // 此时case后必须是判断表达式,为true时进入
fmt.Println("positive")
case a < 0:
fmt.Println("negative")
default:
fmt.Println("zero")
}
go语言中switch不像其他语言,需要在case后加break防止 case穿透
go语言,不需要加break,是不会有case穿透的。
如果想在Go语言中实现穿透效果,使用fallthrough穿透当前case语句块。
fallthrough 只能穿透一层,意思是它让你直接执行下一个case的语句,而且不需要判断条件。
for循环
Go
语言的 For
循环有 3 种形式,只有其中的一种使用分号。
-
for init; condition; post { }
-
for condition { }
-
for { }
例子
// 正常for循环
for i := 0; i < 3; i++ {
fmt.Printf("i=%d\t", i)
}
// 变形写法
i := 0
for i < 3 {
fmt.Printf("i=%d\t", i)
i = i + 1
}
// 死循环
for true {
fmt.Println("Hello World")
}
// 或者直接把true也省略
for {
fmt.Println("Hello World")
}
continue
中止当前这一趟循环体的执行,直接执行“循环后操作”后,进入下一趟循环的条件判断。
for i := 0; i < 10; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i)
}
break
终止当前循环的执行,结束了。
for i := 0; ; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i)
if i >= 10 {
break
}
} // 请问执行结果是什么?
除了break,函数的return结束函数执行,当然也能把函数中的循环打断。
goto和label
这是一个被很多语言尘封或者废弃的关键字,它会破坏结构化编程,但是确实能做到便利的无条件跳转。
goto需要配合标签label使用,label就像代码中的锚点,goto将无条件跳到那里开始向后执行代码。
for i := 0; ; i++ {
if i%2 == 0 {
continue
}
fmt.Println(i)
if i > 10 {
goto condition
}
}
condition:
fmt.Println("done")
continue、break也可以指定label,方便某些循环使用。但是,建议不要这么写,弄不好就成了毛线团。
for range
for range
遍历字符串
-
for range
按照字符偏移(rune类型),中文是utf-8
编码,占3个字节 -
len(s)
按照字节偏移(byte类型)
for i, v := range "abcd测试" {
fmt.Printf("%d: %T, %[2]v, %[2]c\n", i, v)
}
fmt.Println("\xe6\xb5\x8b\xe8\xaf\x95")
/*
运行结果如下
0: int32, 97, a
1: int32, 98, b
2: int32, 99, c
3: int32, 100, d
4: int32, 27979, 测
7: int32, 35797, 试
测试
*/
s := "abcd测试"
for i := 0; i < len(s); i++ { //len返回字符串的字节数
fmt.Printf("%d: %T %[2]v, %[2]c\n", i, s[i])
}
/*
运行结果如下
0: uint8 97, a
1: uint8 98, b
2: uint8 99, c
3: uint8 100, d
4: uint8 230, æ
5: uint8 181, µ
6: uint8 139,
7: uint8 232, è
8: uint8 175, ¯
9: uint8 149,
*/