第三篇:循环条件、数组、切片、map
第三篇:循环条件、数组、切片、map
目录
一、条件语句
1 if- else if - else
// 条件语句后不能回车换行,换行会报错
if a > 10 {
fmt.Println("a大于10")
}else if a < 10 {
fmt.Println("a小于10")
}else {
fmt.Println("a等于10")
}
2 switch
//1 基本使用
num:=4
switch num {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
case 3:
fmt.Println("3")
case 4:
fmt.Println("4")
}
// 2 默认情况
num:=40
switch num {
case 1:
fmt.Println("1")
case 2:
fmt.Println("2")
case 3:
fmt.Println("3")
case 4:
fmt.Println("4")
default: // 默认情况
fmt.Println("我没有匹配")
}
//3 多表达式判断
num:=40
switch num {
case 1,2,3,4,5,6,7,8: // 多表达式判断
fmt.Println("1")
case 10,11,16:
fmt.Println("2")
case 30:
fmt.Println("3")
case 40,44,45:
fmt.Println("4")
default:
fmt.Println("我没有匹配")
}
//4 无表达式的 switch
num:=80
switch {
case num==12,num==13:
fmt.Println("12,13")
case num==40,num==41:
fmt.Println("40,41")
default:
fmt.Println("我没有匹配")
}
//5 fallthrough 其它语言中是break,go中确是fallthrough
num:=12
switch {
case num==12,num==13:
fmt.Println("12,13")
fallthrough
case num==40,num==41:
fmt.Println("40,41")
//fallthrough //穿透,只要看到fallthrough,无条件执行下一个case或者default
default:
fmt.Println("我没有匹配")
}
二、循环语句
go语言没有while,没有do while循环,只有for循环。
// 基本语法:
for 变量初始化; 条件; 变量自增/自减{
循环体内容
}
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
for i:=0; i<10; i++{
fmt.Println(i)
}
// 省略1部分
i:=0 // 作用域范围大,不止在for内部,外部也可以用
for ;i<10;i++{
fmt.Println(i)
}
// 省略1和3部分
i:=0 //作用域范围大,不止在for内部,外部也可以用
for ;i<10;{
fmt.Println(i)
i++
}
// 省略1和3部分的简略写法
i:=0
for i<10 { // 这就变成了while循环
i++
}
// 省略所有部分
for { // 死循环
}
break:结束本次for循环,continue结束本次循环,继续下一次循环。【python中也是很奇怪,while和for后面还可以加个else,哈哈】
goto:饱受诟病 Java中的保留字,没有实际作用。
三、数组使用
1 数组的基本使用
1.1 一维数组
数组是基础数据类型,并没有那些方法【其实在使用中,很少会用到数组之类的,因为python中就是list、dict,Java中就是ArrayList、HashMap,基本都是使用可变数据类型】。数组是同一类型元素的集合。可以放多个值,但是类型一致,内存中连续存储。Go 语言中不允许混合不同类型的元素。Java也不允许【python的中列表中可以存放不同的值,因为其存放的是引用】
// 1 数组的定义
var names [3]string // 定义了一个大小为3的string类型的数组,类型为[3]string
fmt.Println(names) // [ ] 打印出3个空字符
var nums [3]int
fmt.Println(nums) // [0 0 0]
// 2 数组赋值
nums[1] = 100
// 3 定义并初始化
var nums [3]int = [3]int{1, 2, 3}
var nums = [3]int{1, 2, 3}
nums := [3]int{1, 2, 3} // 如此书写,所以赋值前必须加上[3]int
// 4 数组定义并初始化的其他方式
var args = [...]int{1,2,3,4,5,6,7} // 数组只要定义,长度就固定 ...只是省略书写数字而已【...只支持var args 和 args:=两种方式】
fmt.Println(ages)
// 5 查看数组的长度
len(args) // python也是len();java中是.length;
// 6 数组的大小是类型的一部分
var a [3]int // 两个类型并不相同;同一个类型才能够进行相互赋值
var b [2]int
// 数组是值类型【函数传递的时候,并不是引用类型】,也就是执行的时候会进行值的拷贝。
// 其实所有函数传参,都是copy传递,值类型的话,直接copy值,引用的话,就是copy引用。
python中的不可变类型: 数值、字符串、元组、布尔
可变类型:列表、字典
// 数组长度 len(nums) 内置函数,都在builtin包中
// 7 数组循环
var nums = [...]int{1, 2, 3, 4, 5}
// 1)普通循环
for i:=0; i<len(nums); i++{
fmt.Println(nums[i])
}
// 2)range循环【python中range是内置函数,go中range是一个关键字,不能加()】
var nums = [...]int{111, 222, 333}
// 一个接受为索引;两个接受为索引和值【不想要索引直接_】
for index, value := range nums{
fmt.Println(index, value) // index为索引,value为值【比较神奇】
}
// 0 111
// 1 222
// 2 333
1.2 多维数组
// 1 基本定义
var a [3][3]int //定义
a[0][1]=99 //使用
fmt.Println(a) // [[0 99 0] [0 0 0] [0 0 0]]
// 2 定义并赋初值
var a [3][3]int=[3][3]int{{1},{1,2,3},{4,4,4}} // [[1 0 0] [1 2 3] [4 4 4]]
var s =[3][3]string{{"yangyi","xxx","yyy"},{},{}} // [[yangyi xxx yyy] [ ] [ ]]
// 3 循环多维数组
for _,value:=range s{
for _,in_value:=range value{
fmt.Println(in_value)
}
}
// 4 数组定义并指定位置初始化
var names [100]int=[100]int{10:99,99:99} // 将索引为10和99的位置处置为99
var names [100]int=[100]int{10,11,2,44,99:99,45:88}
// 数组中不仅可以存放基本数据类型,还可以存放结构体【厉害呀,像c、java中,数组仅仅能存放基本数据类型】
var a [4]Person = [4]Person{{},{},{},{}} // 数组中也可以存放结构体类型
四、切片
虽然数组看上去虽然很灵活,但是它们具有固定长度的限制,这边要用到切片。
切片是由数组组成的一种方便的、灵活且功能强大的包装(wrapper)。切片本身不拥有任何数据,它们只是对现有数组的引用。【PS:字符串的切片还是切片】
- 可以声明一个未指定大小的数组来定义切片
- 使用make()函数来创建切片
- 通过对数组的引用来定义切片
// 1 切片定义的第一种方式
var a = [10]int{9,8,7,6,5,4,3,2,1,0}
fmt.Printf("%T\n", a) // [10]int 数组
b := a[:] // 基于数组类型,做一个切片
fmt.Printf("%T\n", b) // []int 切片类型【只要不写东西,就是切片】
// 定义一个切片类型
var b []int
b = a[:]
// 2 修改切片,会影响数组
fmt.Println(b[0]) // 9 【这里和数组使用方式一样】
b[0] = 999 // 切片修改
fmt.Println(a) // [999 8 7 6 5 4 3 2 1 0] 与Python不同,
fmt.Println(b) // [999 8 7 6 5 4 3 2 1 0] Python修改切片,不会对原数据进行影响
// 4 修改原数组,肯定也会影响切片【相互影响】
// 5 一般使用方式
var b []int
res := append(b, 1, 2 ,3 ,4, 5, 6, 7)
fmt.Println(res) // [1 2 3 4 5 6 7]
// 6 只切数组一部分,并修改值
var a = [10]int{9,8,7,6,5,4,3,2,1,0}
var b []int = a[3:5] // [6 5]
b[0] = 999
fmt.Println(a) // [9 8 7 999 5 4 3 2 1 0]
fmt.Println(b) // [999 5]
a[4] = 888
fmt.Println(a) // [9 8 7 999 888 4 3 2 10]
fmt.Println(b) // [999 888]
// 7 当多个切片共用相同的底层数组时,每个切片所做的更改将反映在数组中
var a =[10]int{9,8,7,6,5,4,3,2,1,0}
var b []int=a[3:5]
var c []int=a[4:6]
fmt.Println(a) // [9 8 7 6 5 4 3 2 1 0]
fmt.Println(b) // [6 5]
fmt.Println(c) // [5 4]
b[1]=555
fmt.Println(a) // [9 8 7 6 555 4 3 2 1 0]
fmt.Println(b) // [6 555]
fmt.Println(c) // [555 4]
// 8 切片的长度和容量
var a =[10]int{9,8,7,6,5,4,3,2,1,0}
var b []int = a[3:5]
// 切片的长度
fmt.Println(len(b)) // 2
// 切片的容量(我最多能存多少值)
fmt.Println(cap(b)) // 7 【指针往后的个数】
var a =[10]int{9,8,7,6,5,4,3,2,1,0}
var b []int = a[:]
// 切片的长度
fmt.Println(len(b)) // 10
// 切片的容量(我最多能存多少值)
fmt.Println(cap(b)) // 10
// 9 切片追加值【也就是说,即便只切了1个元素,在进行追加的时候,还是会从容量中进行更改,当容量越界的时候,继续进行追加,会将切片的容量置为原来的2倍】
// 原长度为3,原容量为3;追加一个元素越界之后,长度为4,容量为6
b = append(b, 3) // 追加元素
切片是中括号中没有东西
不存储数据,对底层数据的引用
// 第一种方式:
var slice1 []int // 一个切片在未初始化之前默认为 nil,长度为 0
// 第二种方式: make初始化
var slice1 []int = make([]int, 5) // 切片类型 长度
var slice2 []int = make([]int, 5, 10) // 切片类型 长度 容量
fmt.Println(slice1) // [0 0 0 0 0]
fmt.Println(slice2) // [0 0 0 0 0]
append() // 追加 超过容量,自动扩容,原理容量的两倍
// 切片是引用类型,空值是nil,当作参数传递(append扩容,有可能会出问题)
// 删除元素
args := []string{"111", "222", "333", "444"}
args = append(args[:2], args[3:]... )
fmt.Println(args) // [111 222 444]
// copy()
copy(numbers1,numbers) // copy(numbers1,numbers)
// 多维切片
var slice4 [][]int
五、map
Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。
/* 第一种初始化方式: key值为字符串,value值可以很复杂,数组、切片、map等等 */
var person = make(map[string]string)
// 添加元素
person["name"] = "yangyi"
person["age"] = "18"
person["hobby"] = "song"
/* 第二种初始化方式 */
person := map[string]string{"name": "yangyi", "age": "18", "hobby": "song"}
// 查找元素
fmt.Println(person) // map[age:18 hobby:song name:yangyi] 无序
fmt.Println(person["name"]) // yangyi
fmt.Println(person["hello"]) // 没有不报错
v, flag := person["hello"] // 取值,如果不存在会返回value值的空置【Python没有会报错】 可以使用value, ok := person["name"]
fmt.Println(flag) // false
// 删除元素
delete(person, "hobby")
fmt.Println(person) // map[age:18 name:yangyi]
// 遍历字典
for index, value := range person{
fmt.Println("index=", index, " value=", value)
}
// index= name value=yangyi
// index= age value=18
两个map是引用类型,引用类型比较只能跟nil
进行比较。
切片和map只有添加和删除方法没有,像python中那么多的方法。
六、可变长参数
函数可变长参数:...可以当作形参来用,实参如果是...,表示打散之后传进入。
// 形参使用
func test(name ...int) { // 变量名 ...变量类型 代表可变长参数
fmt.Println(name)
}
test(1, 2, 3,4, 5, 6) // [1 2 3 4 5 6]
// 实参使用
func test(name ...int) {
fmt.Println(name)
}
slice1 := make([]int, 5)
test(slice1...) // 传入切片,后跟...,代表将切片打散
七、指针
& 放在变量前,表示取该变量的地址
* 放在类型前,表示指向该类型的指针(变量定义,指定类型时才会用到)
* 放在变量前,表示解引用(取出指针指向的具体的值)
// *[3]int : 指向该数组的指针
// [3]*int : 数组中放了3个int类型的指针
func main() {
var a []int = []int{111, 222 , 333}
var b *[]int
b = &a
test(b)
}
func test(num *[]int) {
fmt.Println(num) // &[111 222 333]
fmt.Printf("%T\n", num) // *[]int
(*num)[0] = 666 // 先解引用,在复制
fmt.Println(num) // &[666 222 333]
fmt.Println(*num) // [666 222 333]
}