控制流程
go 语言的控制流程语句与 js 相似,需要注意的是语法上的不同。下面是控制流程写法的例子。
- if-else 条件判断的使用
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
if scoer, _ := strconv.Atoi(os.Args[1]); scoer < 60 {
fmt.Println("bad")
} else {
fmt.Println("good")
}
}
// go run .\06\switch\geometry.go 20
// bad
// go run .\06\switch\geometry.go 80
// good
os.Args 变量包含传递给程序的每个命令行参数。这些值的类型为 string。
- for 循环的使用
package main
import ( "fmt" )
func main() {
for i := 0; i < 10; i += 2 {
fmt.Println(i)
}
}
- switch 的使用
package main
import (
"fmt"
"math/rand"
"time"
)
// 生成 max 以内的随机数
func randNum(max int32) int32 {
sec := time.Now().Unix()
rand.Seed(sec)
return rand.Int31n(max)
}
func main() {
num := randNum(10)
switch num {
case 1:
fmt.Println("one...")
case 2:
fmt.Println("two...")
default:
fmt.Println("other", num)
}
}
- fallthrough 关键字
- defer关键字
defer是Go语言中的延迟执行语句,用来添加函数结束时执行的代码,常用于释放某些已分配的资源、关闭数据库连接、断开socket连接、解锁一个加锁的资源。
下面例子是关于文件读写的例子,在完成文件操作后,关闭文件,释放资源。
package main
import (
"fmt"
"io"
"os"
)
func main() {
newfile, error := os.Create("learnGo.txt")
if error != nil {
fmt.Println("Error: Could not create file.")
return
}
defer newfile.Close()
if _, error = io.WriteString(newfile, "Learning Go!"); error != nil {
fmt.Println("Error: Could not write to file.")
return
}
newfile.Sync()
}
- panic() panich函数使程序中断
特殊的数据结构
1、数组
练习 - 使用数组 - Learn | Microsoft Docs
- 初始化时需定义长度和类型,不可改变长度
- 会默认分配零值,不同类型的零值参考基本类型
定义数组:
-
基本
var a [3]int a[1] = 1 a[2] = 2 fmt.Println(a[0], a[1], a[len(a)-1]) // 0 1 2 -
赋初始值
数组长度为3,但这里只给了两个初始值所以打印出的数据后面有个空格
name := [3]string{"zhangsan", "lisi"} fmt.Println(name) //[zhangsan lisi ] -
不指定长度,根据数据多少来确定数组长度
可以看到这里的打印的结果中没有空格了,数组的长度是2
name2 := [...]string{"zhangsan", "lisi"} fmt.Println(name2, len(name2)) //[zhangsan lisi] 2 -
指定位置赋值
定义一个没有指定长度的 string 类型的数组 name3,并在数组下标为 3 的地方赋值 codeniu,程序推断出数组长度为 4
name3 := [...]string{3: "codeniu"} fmt.Println("first index:", name3[0]) fmt.Println("last index:", name3[len(name3)-1]) fmt.Println(name3, len(name3)) //first index: //last index: codeniu //[ codeniu] 4
2、切片
练习 - 了解切片 - Learn | Microsoft Docs
- 切片跟数组相同,但是与数组更重要的区别是切片的大小是动态的
- 可以使用相同的方式去声明切片和数组
切片的三要素
- 基础数组 array
- 切片的长度 len(s):切片中元素的个数
- 切片的容量 cap(s):切片开头与基础数组结束之间的元素数目
切片的语法:s[i:p]
- s 数组
- i 起始指针
- p 结束指针
切片可以理解为从一个数组上切下来一部分,数组 array := [12]int{1,2...12}, 切片 quarter1 := array[0:3], 从0 开始切直到下标为3时停止,quarter1 的元素为[1,2,3], 长度 len(quarter1) 是 3,cap(quarter1) 是 12。
容量为什么是 12 呢?原因是基础数组有更多元素或位置可供使用,但对切片而言不可见。可以这么理解,容量就是数组长度 - 切片的起始指针。
例如:quarter2 := array[3:6],长度为 3,容量为 9( len(array) - i ).
拓展切片:
package main
import "fmt"
func main() {
months := []string{"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}
quarter2 := months[3:6]
quarter2Extended := quarter2[:4]
fmt.Println(quarter2, len(quarter2), cap(quarter2))
fmt.Println(quarter2Extended, len(quarter2Extended), cap(quarter2Extended))
}
// 这个操作将切片 quarter2 的长度拓展为 4
删除项:
Go 没有内置函数用于从切片中删除元素。设计一个函数用于删除切片中指定下标的元素。内置函数 append(slice, element)便于你向切片添加元素。
package main
import "fmt"
func main() [] {
letters := [...]int{1,2,3,4}
remove = 2
if remove < len(letters) {
fmt.Println("Before", letters, "Remove ", letters[remove])
letters = append(letters[:remove], letters[remove+1:]...)
fmt.Println("After", letters)
}
}
备份:
在切片的中更改元素会影响到原始数组
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3, 4}
var slice1 = a[0:2]
var slice2 = a[1:4]
slice1[1] = 100
fmt.Println(a)
fmt.Println(slice1)
fmt.Println(slice2)
}
输出:
[1 100 3 4] [1 100] [100 3 4]
创建副本后再更改可以消除影响
make() 内置函数 make([]type,length) 用于生成一个空切片
copy() 内置函数 copy(dst, src []Type) 用于创建切片的副本,参数分别为目标切片和原切片
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3, 4}
var slice1 = a[0:2]
slice2 := make([]int, 3)
copy(slice2, a[1:4])
slice1[1] = 100
fmt.Println(a)
fmt.Println(slice1)
fmt.Println(slice2)
}
输出:
[1 100 3 4] [1 100] [2 3 4]
3、映射
练习 - 使用映射 - Learn | Microsoft Docs
如何理解 Go 中的映射?
是键值对的集合,映射中所有的键的类型必须相同,他们值得类型也必须相同,但是键与值可以是不同得类型。
声明和初始化:
map 关键字,map[T]T 第一个 T 表示键得类型,第二个 T 表示值得类型。
package main
import "fmt"
func main() {
studentsAge := map[string]int{
"john": 32,
"bob": 31,
}
fmt.Println(studentsAge)
}
只声明不初始化:
var studentsAge map[string]int
// or
studentsAge := make(map[string]int)
需要注意得是,通过 (var studentsAge map[string]int) 这种方式创建得映射叫做 nil 映射,映射不能进行添加操作,否则会报错。
package main
import "fmt"
func main() {
var studentsAge map[string]int
studentsAge["john"] = 32
studentsAge["bob"] = 31
fmt.Println(studentsAge)
}
输出:
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
/Users/johndoe/go/src/helloworld/main.go:7 +0x4f
exit status 2
此规则仅适用于添加项的情况。 如果在 nil 映射中运行查找、删除或循环操作,Go 不会执行 panic。
访问项:
Go 中映射得访问与 JS 中类似,访问映射中没有的项时 Go 不会返回错误。但有时需要知道某个项是否存在。 在 Go 中,映射的下标表示法可生成两个值。 第一个是项的值。 第二个是指示键是否存在的布尔型标志。
package main
import "fmt"
func main() {
studentsAge := make(map[string]int)
studentsAge["john"] = 32
studentsAge["bob"] = 31
age, exist := studentsAge["christy"]
if exist {
fmt.Println("Christy's age is", age)
} else {
fmt.Println("Christy's age couldn't be found")
}
}
删除项:
使用内置函数 delete() ,如果你尝试删除不存在的项,Go 不会执行 panic。
delete(studentsAge, "john")
映射中的循环:
使用rang 关键字,range 会首先生成项的键,然后再生成该项的值。 可使用 _ 变量忽略其中任何一个
package main
import (
"fmt"
)
func main() {
studentsAge := make(map[string]int)
studentsAge["john"] = 32
studentsAge["bob"] = 31
for name, age := range studentsAge {
fmt.Printf("%s\t%d\n", name, age)
}
}
本文正在参加技术专题18期-聊聊Go语言框架