第三篇:循环条件、数组、切片、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]
}
posted @ 2023-04-03 20:41  YangYi215  阅读(39)  评论(0编辑  收藏  举报