1.指针
func main() {
var a int = 10
//每个变量有2层含义,变量的内存,变量的地址
fmt.Printf("a =%d\n", a)
fmt.Printf("&a =%v\n", &a)
//保存某个变量的地址,需要指针类型,
//*int保存int的地址,**int保存*int的地址
var p *int
//声明(定义),定义只是特殊的声明
p = &a //指针变量指向谁,就把谁的地址赋值给指针变量
fmt.Printf("p =%v, &a =%v\n", p, &a)
*p =666 //*p操作的不是内存,是p所指向的内存(就是a)
fmt.Printf("p =%v, a =%v\n", *p, a) //666 666
}
go语言虽然保留指针,但与其它编程语言不同的是
1)默认值是nil,没有NULL常量
2)操作符"&“是取变量地址,”*“通过指针访问目标对象
3)不支持指针运算,不支持 “->” 运算符,直接用”."访问目标成员
go语言指针定义
func main() {
var p *int
p = new(int) //new一个新空间,go语言不需要释放
q := new(int)
}
指针交换a,b值
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)
}
一维数组赋值
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)
//部分初始化,没有初始化的元素自动赋值为0
c := [5]int{1,2,3}
fmt.Println("c =", c)
//指定某个元素初始化
d := [5]int{2:10, 4:10}
fmt.Println("d =", d)
}
二维数组赋值
func main() {
//二维数组初始化,可部分初始化,没有初始化的值为0
e := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 20, 32, 53}}
fmt.Println(e)
//部分初始化,只对第二行元素赋值
f := [3][4]int{1: {5, 6, 7, 8}}
fmt.Println(f)
}
两数组间支持比较和赋值,只支持 == 或 !=,比较是不是每个元素都一样,两个数组比较,数组类型要一样。
2.随机数生成与冒泡排序
func main() {
//设置种子,只需一次
//如果种子参数一样,每次允许程序产生的随机数都一样
//解决办法,用时间
rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数
var a [10]int
n := len(a)
for i:=0; i < n; i++{
//产生随机数
//fmt.Println("rand = ", rand.Int()) //随机很大的数
a[i]= rand.Intn(100)
fmt.Printf("%d, ", a[i]) //Intn函数,限定随机数生成的范围
}
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.Println("有序后:")
for i:=0; i < n; i++{
fmt.Printf("%d, ", a[i]) //Intn函数,限定随机数生成的范围
}
}
数组做函数参数,它是值传递。实参数组的每个元素给行参数组拷贝一份。如果需要用函数改变数组的值,用指针。
//数组做函数参数,它是值传递
//实参数组的每个元素给行参数组拷贝一份
func modify(p *[5]int) {
(*p)[0] = 666
fmt.Println("*a = ", *p)
}
func main() {
a :=[5]int{1,2,3,4,5}
modify(&a)
fmt.Println(a)
}
2.切片
func main() {
array := [...]int {10, 20, 30, 0, 0}
s := array[0:3:5]
//[low:high:max]
//low下标的起点
//high下标的终点(不包括此下标),左闭右开
//len=high-low
//cap = max - low 容量
fmt.Println("s = ", s)
fmt.Println("len(s) = ", len(s)) //长度=3-0
fmt.Println("cap(s) = ", cap(s)) //容量=5-0
//切片与数组的区别
//数组[]里面的长度是固定的一个常量,数组不能修改长度,len和cap永远固定
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) //给切片末尾增加一个成员
}
切片的创建
//自动推导类型,同时初始化
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))
//容量可缺省,缺省时容量等于长度
切片操作
array := []int{0,1,2,3,4,5,6,7,8,9}
s1 := array[:] //[0:len(array):len(array)],不指定时容量和长度一样
fmt.Println(s1)
fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))
//操作某个元素,和数组操作方式一样
data := array[0]
fmt.Println(data)
s2 := array[3:6:7]
fmt.Printf("len = %d, cap = %d\n", len(s2), cap(s2))
s3 := array[:6] //从0开始,取6个元素,容量为10
fmt.Printf("len = %d, cap = %d\n", len(s3), cap(s3))
s4 := array[3:] //从下标为3开始到结尾
fmt.Println(s4) //取7个元素,容量为7
fmt.Printf("len = %d, cap = %d\n", len(s4), cap(s4))
切片与底层数组的关系
array := []int{0,1,2,3,4,5,6,7,8,9}
//新切片修改后原数组也发生改变
s1 := array[2:5]
s1[1] = 666
fmt.Println(s1)
fmt.Println(array)
fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1))
//另外新切片,切片的切片
s2 := s1[2:7]
s2[2] = 777
fmt.Println(s2)
fmt.Println(array)
使用append函数,如果超过原来的容量,通常以2倍容量扩容
func test(m map[int]string){
delete(m,2)
}
func main() {
var ml map[int]string
fmt.Println("ml =", ml)
//队友map只有len,没有cap
fmt.Println("len =",len(ml))
//可以通过make创建
m2 := make(map[int]string)
fmt.Println("ml =", m2)
fmt.Println("len =", len(m2))
//可通过make创建指定长度,只是指定了容量,长度由map内数据决定
m3 := make(map[int]string,10)
m3[1] = "mike"
m3[20] = "c++"
m3[50] = "go"
fmt.Println("ml =", m3)
fmt.Println("len =", len(m3))
//初始化,且键值唯一
m4 := map[int]string{1: "mike", 2: "go", 3: "c++"}
fmt.Println("m4 =", m4)
//遍历
for key, value := range m4 {
fmt.Printf("%d ====> %s\n", key, value)
}
//如何判断一个key是否存在
//第一个返回值为key所对应的value,第二个返回值为key是否存在的条件,存在ok为true
value, ok := m4[1]
if ok == true{
fmt.Println("m[1] =",value)
}else{
fmt.Printf("key不存在\n")
}
//删除某个值
delete(m4, 1) //删除key为1的内容
fmt.Println(m4)
//将删除操作写在函数内部
test(m4) //在函数内部删除某个key
fmt.Println("m4 = ", m4)
}
2.定义结构体
//结构体类型
//有时我们需要将不同数据类型的数组合成一个有机的整体
//定义一个结构体类型
type Student struct{
id int
name string
sex byte
age int
addr string
}
func main() {
//顺序初始化,每个成员必须初始化
var s1 Student = Student{1,"mike", 'm', 18, "bj"}
fmt.Println("s1 =", s1)
//指定成员初始化,没有初始化
s2 := Student{name: "mike", addr: "bj"}
fmt.Println("s2 =", s2)
//初始化指针变量
var s3 *Student = &Student{1,"mike", 'm', 18, "bj"}
fmt.Println("s3 =", *s3)
s4 := &Student{name: "mike", addr: "bj"}
fmt.Println("s4 =", *s4)
}
结构体指针变量
//1.指针有合法指向后,才操作成员
//先定义一个普通结构体变量
var s Student
//再定义一个指针变量,保存s的地址
var p1 *Student
p1 = &s
//通过指针操作成员,p1.id和(*p).id完全等价,只能用.运算符
p1.id = 1
p1.name = "mike"
p1.sex = 'm'
p1.age = 18
p1.addr = "bj"
fmt.Println("p1 = ",p1)
//2.通过new申请一个结构体
p2 :=new(Student)
p2.id = 1
(*p2).name = "mike"
p2.sex = 'm'
p2.age = 18
p2.addr = "bj"
fmt.Println("p2 = ",p2)
如果想使用别的包的函数,结构体类型,结构体成员
函数名,类型名,结构体成员变量名,首字母必须大写,可见
如果首字母是小写,只能在同一个包里使用