Day_03
1.指针基本操作
package main import "fmt" func main() { var a int //每个变量有2层含义:变量的内存,变量的地址 fmt.Printf("a = %d\n", a) //变量的内存内容 fmt.Printf("&a = %v\n", &a) //变量的内存地址(指针) //保存某个变量的地址,需要指针类型 *int 保存int的地址, **int保存*int的地址 //声明(定义),定义只是特殊的声明 //定义一个变量p,类型为*int var p *int p = &a //指针变量指向谁,就把谁的地址赋值给指针变量 fmt.Printf("p = %v,&a = %v\n", p, &a) *p = 666 //*p操作的不是p的内存,是p所指向的内存(就是a) fmt.Printf("*p = %v,a = %v\n", *p, a) }
2.不要操作没有合法指向的内存
package main import "fmt" func main() { var p *int p = nil fmt.Println("p = ", p) //*p = 666 //err,因为p没有合法指向 var a int p = &a //p指向a *p = 666 fmt.Println("a = ", a) }
3.new函数的使用
package main import "fmt" func main() { var p *int p = new(int) *p = 666 fmt.Println("*p = ", *p) q := new(int) //自动推导类型,更简便 *q = 777 fmt.Println("*q = ", *q) } /* 总结:其实就是c语言的动态地址分配 不过c语言需要释放内存地址从而回收空间(GC) 而Go语言无需担心其内存的生命周期或垃圾回收 Go语言的内存管理系统会自动处理 */
4.普通变量做函数参数(值传递)
package main import "fmt" func swap(a, b int) { a, b = b, a fmt.Printf("swap: a = %d,b = %d\n", a, b) } func main() { a, b := 10, 20 //通过一个函数交换a和b的内容 swap(a, b) //变量本身传递,值传递(站在变量角度) fmt.Printf("main: a = %d,b = %d\n", a, b) } /* 输出结果: swap: a = 20,b = 10 main: a = 10,b = 20 */
5.指针做函数参数(地址传递)
package main import "fmt" func swap(p1, p2 *int) { *p1, *p2 = *p2, *p1 } func main() { a, b := 10, 20 //通过一个函数交换a和b的内容 swap(&a, &b) //内存地址传递 fmt.Printf("main: a = %d,b = %d\n", a, b) } /* 运行结果: main: a = 20,b = 10 这次交换成功了 */
6.为什么需要数组
package main import "fmt" func main() { //定义一个数组id,内有50个元素,[]内不能用常量 var id [50]int //操作数组,通过下标,从0开始,到len()-1 for i := 0; i < len(id); i++ { id[i] = i + 1 fmt.Printf("第一种方式:id[%d] = %d\n", i, id[i]) } //i返回下标,data返回元素 for i, data := range id { id[i] = i + 1 fmt.Printf("第二种方式:id[%d] = %d\n", i, data) } }
7.数组的基本使用(同上)
8.数组的初始化
package main import "fmt" func main() { //声明定义同时赋值,叫初始化 //1.全部初始化 var a [5]int = [5]int{1, 2, 3, 4, 5} fmt.Println("a = ", a) b := [5]int{1, 2, 3, 4, 5} fmt.Println("b = ", b) //2.部分初始化,没有初始化的元素,自动赋值为0 c := [5]int{1, 2, 3} fmt.Println("c = ", c) //3.指定某个元素初始化,2和4代表的是下标 d := [5]int{2: 10, 4: 20} fmt.Println("d = ", d) }
9.二维数组的介绍
package main import "fmt" func main() { //有多少个[]就是多少维 //有多少个[]就用多少个循环 var a [3][4]int k := 0 for i := 0; i < 3; i++ { for j := 0; j < 4; j++ { k++ a[i][j] = k fmt.Printf("a[%d][%d] = %d, ", i, j, a[i][j]) } fmt.Printf("\n") } fmt.Println("a = ", a) //有3个元素,每个元素又是一维数组[4]int,注意这种方式最好不要换行 b := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} fmt.Println("b = ", b) //部分初始化,没有初始化的值为0 c := [3][4]int{{1, 2, 3}, {5, 6, 7, 8}, {9, 10}} fmt.Println("c = ", c) //部分初始化,没有初始化的值为0 d := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}} fmt.Println("d = ", d) //指定下标方式的初始化,没有初始化的值为0 e := [3][4]int{1: {5, 6, 7, 8}} fmt.Println("e = ", e) }
10.数组比较和赋值
package main import "fmt" func main() { a := [5]int{1, 2, 3, 4, 5} b := [5]int{1, 2, 3, 4, 5} c := [5]int{1, 2, 3} fmt.Println("a == b", a == b) //返回true fmt.Println("a == c", a == c) //返回false //同类型的数组可以赋值 var d [5]int d = a fmt.Println("d = ", d) }
11.随机数的使用
package main import "fmt" import "math/rand" import "time" func main() { //设置种子,只需要一次 //如果种子参数一样,每次运行程序产生的随机数都一样,我们可以调用系统的时间,这样每次就都不一样了 rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数 for i := 0; i < 5; i++ { //产生4次随机数 //产生随机数 //fmt.Println("rand = ", rand.Int()) //随机很大的数 fmt.Println("rand = ", rand.Intn(100)) //限制在100以内 } }
12.冒泡排序
package main import "fmt" import "math/rand" import "time" func main() { //设置种子,只需要一次 //如果种子参数一样,每次运行程序产生的随机数都一样,我们可以调用系统的时间,这样每次就都不一样了 rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数 var a [10]int n := len(a) for i := 0; i < n; i++ { a[i] = rand.Intn(100) //100以内的随机数 fmt.Printf("%d,", a[i]) } fmt.Printf("\n") //冒泡排序,挨着的2个元素比较,升序(大于则交换) for i := 0; i < n-1; i++ { for j := 0; j < n-1-i; j++ { if a[j] > a[j+1] { a[j], a[j+1] = a[j+1], a[j] } } } fmt.Printf("\n排序后:\n") for i := 0; i < n; i++ { fmt.Printf("%d,", a[i]) } fmt.Printf("\n") }
13.数组做函数参数
package main import "fmt" //数组做函数参数,它是值传递 //实参数组的每个元素给形参数组拷贝一份 //形参的数组是实参数组的复制品 func modify(a [5]int) { a[0] = 666 fmt.Println("modify a = ", a) } func main() { a := [5]int{1, 2, 3, 4, 5} //初始化 modify(a) //数组传递过去 fmt.Println("main: a = ", a) } /* 运行结果: modify a = [666 2 3 4 5] main: a = [1 2 3 4 5] */
14.数组指针做函数
package main import "fmt" //p指向实现数组a,它是指向数组,它是数组指针 //*p代表指针所指向的内存,就是实参a func modify(p *[5]int) { (*p)[0] = 666 fmt.Println("modify *a = ", *p) } func main() { a := [5]int{1, 2, 3, 4, 5} //初始化 modify(&a) //地址传递 fmt.Println("main: a = ", a) } /* 运行结果: modify *a = [666 2 3 4 5] main: a = [666 2 3 4 5] */
15.切片的长度和容量
package main import "fmt" func main() { a := []int{1, 2, 3, 4, 5} s := a[0:3:5] fmt.Println("s = ", s) //s = [1 2 3] fmt.Println("len(s) = ", len(s)) //长度 len(s) = 3 3-0 fmt.Println("cap(s) = ", cap(s)) //容量 cap(s) = 5 5-0 s = a[1:4:5] fmt.Println("s = ", s) //s = [2 3 4] fmt.Println("len(s) = ", len(s)) //长度 len(s) = 3 4-1 fmt.Println("cap(s) = ", cap(s)) //容量 cap(s) = 4 5-1 }
16.切片的创建
package main import "fmt" func main() { //自动推导类型,同时初始化 s1 := []int{1, 2, 3, 4} fmt.Println("s1 = ", s1) //借助make函数,格式 make(切片类型,长度,容量) s2 := make([]int, 5, 10) fmt.Printf("len = %d,cap = %d\n", len(s2), cap(s2)) //没指定容量,容量和长度一样 s3 := make([]int, 5) fmt.Printf("len = %d,cap = %d\n", len(s3), cap(s3)) } func main_bak() { //切片和数组的区别 //数组[]里面的长度是固定的一个常量,数组不能修改长度,len和cap永远都是5 a := [5]int{} fmt.Printf("len = %d,cap = %d\n", len(a), cap(a)) //切片,[]里面为空,或者为...,切片的长度或容量可以不固定 s := []int{} fmt.Printf("len = %d,cap = %d\n", len(s), cap(s)) s = append(s, 11) //给切片末尾添加一个成员 fmt.Printf("len = %d,cap = %d\n", len(s), cap(s)) }
17.切片的截取
package main import "fmt" func main() { array := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s1 := array[:] //不指定容量,则容量和长度一样 fmt.Println("s1 = ", s1) fmt.Printf("len = %d,cap = %d\n", len(s1), cap(s1)) //操作某个元素,和数组操作方式一样 data := array[0] fmt.Println("data = ", data) s2 := array[3:6:7] //a[3],a[4],a[5] len = 6-3 =3 cap = 7-3=4 fmt.Println("s2 = ", s2) fmt.Printf("len = %d,cap = %d\n", len(s2), cap(s2)) s3 := array[:6] //从0开始,6个元素 常用 fmt.Println("s3 = ", s3) fmt.Printf("len = %d,cap = %d\n", len(s3), cap(s3)) s4 := array[3:] //从下标为3开始,到结尾 fmt.Println("s4 = ", s4) fmt.Printf("len = %d,cap = %d\n", len(s4), cap(s4)) }
18.切片和底层数组的关系
package main import "fmt" func main() { a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} //新切片 s1 := a[2:5] //从a[2]开始,取3个元素 s1[1] = 666 fmt.Println("s1 = ", s1) fmt.Println("a = ", a) //我们发现底层数组也跟着一起改变了 //另外一个新切片 s2 := s1[2:7] s2[2] = 777 fmt.Println("s2 = ", s2) //s2 = [4 5 777 7 8] fmt.Println("a = ", a) //a = [0 1 2 666 4 5 777 7 8 9] }
19.append函数的使用
package main
import "fmt"
func main() {
s1 := []int{}
fmt.Printf("len = %d,cap = %d\n", len(s1), cap(s1))
//在原切片的末尾添加元素
s1 = append(s1, 1)
s1 = append(s1, 2)
s1 = append(s1, 3)
fmt.Println("s1 = ", s1)
fmt.Printf("len = %d,cap = %d\n", len(s1), cap(s1))
}
20.append扩容特点
package main import "fmt" func main() { //如果超过原来的容量,通常以2倍容量扩容 s := make([]int, 0, 1) //容量为1 oldCap := cap(s) for i := 0; i < 20; i++ { s = append(s, i) if newCap := cap(s); oldCap < newCap { fmt.Printf("cap: %d=======> %d\n", oldCap, newCap) oldCap = newCap } } }
21.copy的使用
package main import "fmt" func main() { srcSlice := []int{1, 2} dstSlice := []int{6, 6, 6, 6, 6} copy(dstSlice, srcSlice) //把srcSlice的切片拷贝给dstSlice fmt.Println("dst = ", dstSlice) //dst = [1 2 6 6 6] }
22.切片做函数参数
package main import "fmt" import "math/rand" import "time" func InitData(s []int) { //设置种子 rand.Seed(time.Now().UnixNano()) for i := 0; i < len(s); i++ { s[i] = rand.Intn(100) //产生100以内的随机数 } } //冒泡排序 func BubbleSort(s []int) { n := len(s) for i := 0; i < n-1; i++ { for j := 0; j < n-1-i; j++ { if s[j] > s[j+1] { s[j], s[j+1] = s[j+1], s[j] } } } } func main() { n := 10 //创建一个切片,len为n s := make([]int, n) InitData(s) //初始化数组 fmt.Println("排序前:---->", s) BubbleSort(s) fmt.Println("排序后:---->", s) } //总结:数组是值传递,切片是引用传递
23.猜数字游戏
package main import "fmt" import "math/rand" import "time" func CreateNum(p *int) { //设置种子 rand.Seed(time.Now().UnixNano()) var num int for { num = rand.Intn(10000) //有可能出现231,22这种数字 if num >= 1000 { //只取4位数 break } } //fmt.Println("num = ", num) *p = num } func GetNum(s []int, num int) { s[0] = num / 1000 //取千位 s[1] = num % 1000 / 100 //取百位 s[2] = num % 100 / 10 //取十位 s[3] = num % 10 //取个位 } func OnGame(randSlice []int) { var num int keySlice := make([]int, 4) for { for { fmt.Printf("请输入一个4位数:") fmt.Scan(&num) //999 <= num < 10000 if 999 < num && num <= 10000 { break } fmt.Println("输入的数不符合要求") } fmt.Println("num = ", num) GetNum(keySlice, num) //fmt.Println("keySlice = ", keySlice) n := 0 for i := 0; i < 4; i++ { if keySlice[i] > randSlice[i] { fmt.Printf("第%d位大了一点\n", i+1) } else if keySlice[i] < randSlice[i] { fmt.Printf("第%d位小了一点\n", i+1) } else { fmt.Printf("第%d位猜对了\n", i+1) n++ } } if n == 4 { //4位都猜对了 fmt.Println("全部猜对!!!") break //跳出循环 } } } func main() { var randNum int //产生一个4位的随机数 CreateNum(&randNum) //fmt.Println("randNum = ", randNum) randSlice := make([]int, 4) //保存这个4位数的每一位,利用除法依次除以1000、100、10取商、取余的方式,这里我们将其定义为一个函数 GetNum(randSlice, randNum) //fmt.Println("randSlice = ", randSlice) /* n1 := 1234 / 1000 //取商 n2 := 1234 %1000 / 100 //取余数,结果为234, 234/100取商得到2 fmt.Println("n1 = ",n1) fmt.Println("n2 = ",n2) */ OnGame(randSlice) //游戏函数 }
24.Map的基本使用
package main import "fmt" func main() { //定义一个变量,类型为map[int]string,就是python里面的字典类型 var m1 map[int]string fmt.Println("m1 = ", m1) //对于map只有len,没有cap fmt.Println("len(m1) = ", len(m1)) //可以通过make创建,可以指定长度,只是指定了容量,但是里面却是1个数据也没有 //指定了长度为2,但是会自动扩容,键值必须唯一 m2 := make(map[int]string, 2) m2[1] = "mike" m2[2] = "go" m2[3] = "c++" fmt.Println("m2 = ", m2) fmt.Println("len(m2) = ", len(m2)) //初始化 m3 := map[int]string{1: "mike", 2: "go", 3: "java"} fmt.Println("m3 = ", m3) }
25.Map赋值
package main import "fmt" func main() { m1 := map[int]string{1: "rooney", 2: "yoyo"} //赋值,如果已经存在的key值,修改内容 m1[1] = "Ramos" fmt.Println("m1 = ", m1) m1[3] = "Messi" //追加,map底层自动扩容,和append类似 fmt.Println("m1 = ", m1) }
26.Map遍历
package main import "fmt" func main() { m := map[int]string{1: "rooney", 2: "yoyo", 3: "go"} //第一个返回值为key,第二个返回值为value,遍历结果是无序的 for key, value := range m { fmt.Printf("%d ===========>%s\n", key, value) } //如何判断一个key值是否存在 //第一个返回值为key值所对应的value,第二个返回值为key是否存在的条件, //存在ok为true value, ok := m[1] if ok == true { fmt.Println("m[1] = ", value) } else { fmt.Println("key不存在") } }
27.Map删除
package main import "fmt" func main() { m := map[int]string{1: "rooney", 2: "yoyo", 3: "go"} fmt.Println("m = ", m) delete(m, 1) //删除key为1的内容 fmt.Println("m = ", m) }
28.Map做函数参数
package main import "fmt" func test(m map[int]string) { delete(m, 1) } func main() { m := map[int]string{1: "mike", 2: "yoyo", 3: "go"} fmt.Println("m = ", m) test(m) //在函数内部删除某个key fmt.Println("m = ", m) }
29.结构体普通变量初始化
package main import "fmt" //定义一个结构体类型 type Student struct { id int name string sex byte //字符类型 age int addr string } func main() { //顺序初始化,每个成员都必须初始化,字符类型的会以ascii码来打印 var s1 Student = Student{1, "mike", 'm', 18, "sz"} fmt.Println("s1 = ", s1) //指定成员初始化,没有初始化的成员自动赋值为0 s2 := Student{name: "mike", addr: "bj"} fmt.Println("s1 = ", s2) }
30.结构体指针变量初始化
package main import "fmt" //定义一个结构体类型 type Student struct { id int name string sex byte //字符类型 age int addr string } func main() { //这次初始化就变成了指针形式了, &取地址,*代表指针 var p1 *Student = &Student{1, "mike", 'm', 18, "sz"} fmt.Println("*p1 = ", *p1) //这里也可以不加*,go会自动识别 p2 := &Student{name: "mike", addr: "bj"} fmt.Printf("p2 type is %T\n", p2) fmt.Println("*p2 = ", *p2) }
31.结构体成员的使用:普通变量
package main import "fmt" //定义一个结构体类型 type Student struct { id int name string sex byte //字符类型 age int addr string } func main() { //定义一个结构体普通变量 var s Student //操作成员,需要使用点(.)运算符 s.id = 1 s.name = "mike" s.sex = 'm' //字符 s.age = 19 s.addr = "sz" fmt.Println("s = ", s) }
32.结构体成员的使用:指针变量
package main import "fmt" //定义一个结构体类型 type Student struct { id int name string sex byte //字符类型 age int addr string } func main() { //1.指针有合法指向后,才操作成员 //先定义一个普通结构体变量 var s Student //再定义一个指针变量,保存s的地址 var p1 *Student p1 = &s //通过指针操作成员 p1.id 和(*p1).id完全等价,只能使用.运算符 p1.id = 18 (*p1).name = "mike" p1.sex = 'm' p1.age = 19 p1.addr = "bj" fmt.Println("p1 = ", p1) //2.通过new申请一个结构体 p2 := new(Student) p2.id = 25 (*p2).name = "Rooney" p2.sex = 'f' p2.age = 27 p2.addr = "sz" fmt.Println("p2 = ", p2) }
33.结构体比较和赋值
package main import "fmt" //定义一个结构体类型 type Student struct { id int name string sex byte //字符类型 age int addr string } func main() { s1 := Student{1, "mike", 'm', 18, "bj"} s2 := Student{1, "mike", 'm', 18, "bj"} s3 := Student{2, "mike", 'm', 18, "bj"} fmt.Println("s1 == s2", s1 == s2) fmt.Println("s1 == s3", s1 == s3) //同类型的2个结构体变量可以相互赋值 var tmp Student tmp = s3 fmt.Println("tmp = ", tmp) }
34.结构体做为函数参数
package main import "fmt" //定义一个结构体类型 type Student struct { id int name string sex byte //字符类型 age int addr string } func test01(s Student) { s.id = 666 fmt.Println("test01: ", s) } func test02(p *Student) { p.id = 888999 fmt.Println("test02: ", *p) } func main() { s := Student{1, "mike", 'm', 18, "sz"} test01(s) //值传递,形参无法改实参 fmt.Println("main(test01): ", s) test02(&s) //地址传递,形参可以改实参 fmt.Println("main(test02): ", s) }
35.可见性
如果想使用别的包的函数、结构体、结构体成员 函数名、类型名、结构体成员变量名、首字母必须大写,可见 如果首字母是小写,只能在同一个包里使用