1.指针
【1】指针
指针是一个代表着某个内存地址的值。这个内存地址往往是在内存中存储的某一个变量的值的起始位置。
Go语言对指针的支持介于java和C/C++语言之间基本操作:
- 默认值为nil,没有NULL常量
- 操作符"&"取地址,"*"通过指针访问目标对象
- 不支持指针运算,不支持"->"运算符,直接用"."访问目标成员
package main
import (
"fmt"
)
func main() {
var i int = 10
var p *int //p为int类型的指针
p = &i //p指向i的地址
fmt.Printf("i的值为%d,地址为%v,取地址后的值为%v\n", i, &i, *p)
}
【2】new函数的使用
表达式new(T)将构建一个T类型的匿名变量,所做的是为T类型的新值分配并清零一块内存空间,然后返回这块内存的地址,返回的指针类型为*T。
package main
import (
"fmt"
)
func main() {
p := new(int)
*p = 666
fmt.Printf("*p的值为%d,地址为%v\n", *p, p)
}
【3】指针用作函数参数
package main import ( "fmt" ) //变换两个变量的值 func swap(a, b *int) { //传入a,b地址指针 *a, *b = *b, *a //更改指针地址内存空间的值 fmt.Printf("swap: a=%d,b=%d\n", *a, *b) } func main() { a, b := 10, 20 swap(&a, &b) //调用函数调换;两个变量的值 fmt.Printf("main: a=%d,b=%d\n", a, b) }
输出:
2.数组
【1】数组的基本操作
package main import ( "fmt" ) func main() { var temp [20]int //定义数组temp,数组定义时[]内必须是常量 for i := 0; i < len(temp); i++ { //遍历数组 temp[i] = i + 1 fmt.Printf("temp[%d]=%d\n", i, temp[i]) } }
输出:
【2】数组的初始化
package main import ( "fmt" ) func main() { //1.全部初始化 var a [5]int = [5]int{1, 2, 3, 4, 5} fmt.Println(a) b := [5]int{1, 2, 3, 4, 5} fmt.Println(b) //2.部分初始化 c := [5]int{1, 2, 3} fmt.Println(c) //3.指定某个元素初始化 d := [5]int{2: 10, 4: 20} fmt.Println(d) }
输出:
【3】二维数组
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, k) } fmt.Printf("\n") } fmt.Println("a=", a) //1.全部初始化 b := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}} fmt.Println("b=", b) //2.部分初始化 c := [3][4]int{{1, 2, 3, 4}, {5, 6, 7}} fmt.Println("c=", c) //3.指定位置初始化 d := [3][4]int{1: {5, 6, 7, 8}} fmt.Println("d=", d) }
输出:
【4】数组的比较和赋值
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) fmt.Println("b==c:", b == c) //同类型的数组可以赋值 d := [5]int{} d = a fmt.Println("d=", d) }
输出:
【5】随机数的生成
package main import ( "fmt" "math/rand" "time" ) func main() { //设置种子 //如果种子参数一样,每次运行程序产生的随机数都是一样 rand.Seed(time.Now().UnixNano()) //种子随时间变 //rand.Seed(666) //固定种子 //产生随机数 for i := 0; i < 5; i++ { fmt.Println("rand=", rand.Int()) //随机很大的数 fmt.Println("rand=", rand.Intn(100)) //限制在100以内的数 } }
输出:
【6】数组作为函数参数
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) }
输出:
【7】数组指针做函数参数
package main import ( "fmt" ) //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) }
输出:
3.切片
【1】概述
数组的长度在定义之后就不能改变,数值是值类型,每次传递都将产生一个副本。为了解决这个问题,Go语言中通过切片(slice)来弥补数组的不足,切片并不是数组或者数组指针,它通过内部指针和相关属性引用数组片段,以实现变长方案。
【2】切片的长度和容量
package main import ( "fmt" ) func main() { a := []int{1, 2, 3, 4, 0, 0} //初始化切片,切片[]里面为空或者... s := a[0:3:5] //取切片 fmt.Printf("s=%v,len(s)=%d,cap(s)=%d\n", s, len(s), cap(s)) }
输出:
【3】切片的创建方式
package main import ( "fmt" ) func main() { //传统的创建方式,自动推导类型,同时初始化 s1 := []int{1, 2, 3, 4} fmt.Println("s1=", s1, " len=", len(s1), " cap=", cap(s1)) //借助make函数,格式:make(切片类型,长度,容量) s2 := make([]int, 5, 10) fmt.Println("len=", len(s2), " cap=", cap(s2)) }
输出:
【4】切片的截取
切片操作 语法 含义 s[n] 切片s中索引位置为n的项 s[n:m] 从切片s的索引位置n到m-1处所获得的切片 s[n:] 从切片s的索引位置n到len(s)-1处所获得的切片 s[:m] 从切片s的索引位置0到m-1处所获得的切片 s[:] 从切片s的索引位置0到len(s)-1处所获得的切片 cap(s) 切片s的容量,总是>=len(s) len(s) 切片s中包含项的个数,总是<=cap(s) s[:cap(s)] 增加切片s的长度到其容量
【5】内建函数
- append
append函数向slice切片后面添加元素,返回新的slice,会智能的增长底层数组的容量,通常以两倍容量重新分配底层数组,并复制原来的数据。
package main import ( "fmt" ) func main() { s1 := []int{1, 2, 3} //在原切片的末尾添加元素 s2 := append(s1, 4, 5) fmt.Println("s2=", s2) //如果超过原来的容量,通常以两倍容量扩容 s := make([]int, 0, 1) oldCap := cap(s) for i := 0; i < 8; i++ { s = append(s, i) if newCap := cap(s); oldCap < newCap { fmt.Printf("cap: %d ===> %d\n", oldCap, newCap) oldCap = newCap } } }
输出:
- copy函数
在两个slice之间赋值数据赋值长度以len小的为基准,连个slice可以同时指向同一底层数组。
package main import ( "fmt" ) func main() { dstslice := []int{1, 2} srcslice := []int{6, 6, 6, 6, 6} copy(dstslice, srcslice) fmt.Printf("dst = %d\n", dstslice) }
输出:
【6】切片做函数参数
package main import ( "fmt" "math/rand" "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-i-1; j++ { if s[j] > s[j+1] { s[j], s[j+1] = s[j+1], s[j] } } } } func main() { n := 10 s := make([]int, n) InitData(s) //初始化数组 fmt.Println("排序前:", s) Bubblesort(s) //冒泡排序 fmt.Println("排序后:", s) }
输出:
4.map
【1】map的初始化和赋值
map是一组无序的key-value键值对集合,切片、函数以及包含切片的结构类型,不能作为map的键。
package main import ( "fmt" ) func main() { //定义一个变量,类型为map[int]string var dict map[int]string //对于map只有len,没有容量 fmt.Printf("dict = %v,len = %v\n", dict, len(dict)) //可以通过make创建 m1 := make(map[int]string) fmt.Printf("m1 = %v,len = %v\n", m1, len(m1)) //可以通过make创建并指定长度,只是指定了容量,但是里面并没有数据,故长度为0 m2 := make(map[int]string, 10) m2[1] = "mike" //元素操作,赋值,如果key值已经存在,则会更改value m2[2] = "go" //如果不存在key,则增加键值对。 m2[3] = "c++" fmt.Printf("m2 = %v,len = %v\n", m2, len(m2)) //初始化,键值是唯一的 m3 := map[int]string{1: "mike", 2: "go", 3: "c++"} fmt.Println("m3=", m3) }
输出:
【2】遍历map以及如何判断一个键是否存在
package main import ( "fmt" ) func main() { m := map[int]string{1: "mike", 2: "yoyo", 3: "go"} //第一个返回值为key,第二个返回值为value,遍历结果是无序的 for key, value := range m { fmt.Printf("m[%d]=%s\n", key, value) } //如何判断一个key是否存在 //第一个返回值为key所对应的value,第二个返回值为key是否存在的条件,存在ok为true value, ok := m[1] if ok == true { fmt.Printf("存在,value=%s\n", value) } else { fmt.Printf("不存在\n") } }
输出:
【3】map删除
delete(map, key) //map表示要删除元素的map,key为要删除的键值对的key值。
【4】map做函数参数
进行的是值传递,函数中所进行的操作会影响原来map.
package main import ( "fmt" ) func test(m map[int]string) { delete(m, 1) //删除键值为1的键值对 } func main() { m := map[int]string{1: "mike", 2: "yoyo", 3: "go"} fmt.Println(m) test(m) fmt.Println(m) }
输出:
5.结构体
【1】概述
结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合,每个数据称为结构体的成员。
type Student struct { //学生信息结构体表示方法 id int name string sex byte age int addr string }
【2】结构体初始化
package main import ( "fmt" ) type Student struct { //学生信息结构体表示方法 id int name string sex byte //字符类型 age int addr string } func main() { //顺序初始化,每个成员都要初始化 var s1 Student = Student{1, "wang", 'm', 12, "西安"} fmt.Println(s1) //指定成员初始化,没有初始化的成员自动赋值0 s2 := Student{name: "mike", addr: "bj"} fmt.Println(s2) }
输出:
【3】结构体指针变量初始化
package main import ( "fmt" ) type Student struct { //学生信息结构体表示方法 id int name string sex byte //字符类型 age int addr string } func main() { //顺序初始化,每个成员都要初始化 var s1 *Student = &Student{1, "wang", 'm', 12, "西安"} fmt.Println(*s1) //指定成员初始化,没有初始化的成员自动赋值0 s2 := &Student{name: "mike", addr: "bj"} fmt.Printf("s2 type is %T\n", s2) fmt.Println(*s2) }
输出:
【4】结构体不同成员的使用--普通变量
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 = "wang" s.addr = "bj" s.sex = 'm' fmt.Println(s) }
输出:
【5】结构体不同成员的使用--指针变量
package main import ( "fmt" ) type Student struct { //学生信息结构体表示方法 id int name string sex byte //字符类型 age int addr string } func main() { //指针有合法指向后才操作成员 //先定义一个普通结构体变量 var s Student //再定义一个指针变量,保存s的地址 var p1 *Student p1 = &s //p1.id和(*p1).id完全等价 p1.id = 1 p1.name = "wang" p1.addr = "bj" p1.sex = 'm' fmt.Println("p1=", p1) //方法二,通过new申请一个结构体 p2 := new(Student) p2.id = 1 p2.name = "wang" p2.addr = "bj" p2.sex = 'm' fmt.Println("p2=", p2) }
输出:
【6】结构体的比较
俩个结构体可以使用==和!=进行比较
【7】结构体作为函数参数--值传递
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 main() { s1 := Student{1, "wang", 'm', 12, "bj"} test01(s1) //值传递,形参无法改实参 fmt.Println("main=", s1) }
输出:
【8】结构体作为函数参数--地址传递
package main import ( "fmt" ) type Student struct { //学生信息结构体表示方法 id int name string sex byte //字符类型 age int addr string } func test01(p *Student) { p.id = 666 } func main() { s1 := Student{1, "wang", 'm', 12, "bj"} test01(&s1) //地址传递(引用传递),形参可以改实参 fmt.Println("main=", s1) }
输出:
附加:
如果想使用别的包的函数、结构体、结构体成员,函数名、结构体名、结构体成员名首字母必须大写,如果是小写只能在同一个包内使用。