go语言基础语法:指针,数组,随机数,切片,map,结构体

本文详细介绍了Go语言的基础语法,包括指针的使用,如基本操作、new()函数、作为函数参数;数组的概念和操作,如初始化、比较赋值、作函数参数;随机数的生成和冒泡排序;切片的创建、截取、append函数及其扩容特性;map的创建、赋值、遍历和删除;结构体的初始化、成员使用及做函数参数;最后讲解了Go语言的可见性规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、指针

1.指针的基本操作

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的内存,是p所指向的内存(就是a)
fmt.Printf("*p=%v,a=%v\n", *p, a)

2.不要操作没有合法指向的内存

var p *int
p = nil//p指向空指针
fmt.Println("p=", p)
*p = 666

3.new()函数的使用

var p *int
p=new(int)//申请一个合法内存
//无需担心其内存的生命周期或删除问题,内存管理系统会自动回收
*p=666
fmt.Println("*p=",*p)

4.普通变量做函数参数

func main() {
	a, b := 10, 20
	swap(a, b)//通过一个函数交换a和b的内容
	fmt.Printf("main:a=%d,b=%d\n", a, b)
}
func swap(a, b int) {//形参,值传递
	a, b = b, a
	fmt.Printf("swap:a=%d,b=%d\n", a, b)
}

5.指针作函数参数

func main() {
	a, b := 10, 20
	swap(&a, &b)//地址传递
	fmt.Printf("main:a=%d,b=%d\n", a, b)
}
func swap(a, b *int) {
	*a, *b = *b, *a
	fmt.Printf("swap:a=%d,b=%d\n", *a, *b)
}

二、数组

1.数组的必要性

作为同一类型数据的集合,数组的操作要比单独操作数据简便灵活

var id [50]int
for i := 0; i < len(id); i++ {
	id[i] = i + 1
	fmt.Printf("id[%d]=%d\n", i, id[i])
}

2.数组的基本使用

//[数字],这个数作为数组元素的个数
var a [10]int//注意:定义数组时,数组元素的个数必须为常量
var b [5]int
fmt.Printf("len(a)=%d,len(b)=%d\n", len(a), len(b))
//数组下标可以是常量或者变量
a[0] = 1
i := 1
a[i] = 2
//给每个元素赋值
for i := 0; i < len(a); i++ {
	a[i] = i + 1
}
//迭代打印
for i, data := range a {
	fmt.Printf("a[%d]=%d\n", i, data)
}

3.数组的初始化

//声明定义同时赋值,叫初始化
//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: 20}
fmt.Println("d=", d)

4.二维数组

    //有多少个[]就是有多少维,赋值时就用多少个循环
    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.Println()
	}
	fmt.Println("a=", a)
    //有三个元素,每一个元素又是一个一维数组[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)
	d := [3][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
	fmt.Println("d=", d)
	e := [3][4]int{1: {5, 6, 7, 8}}
	fmt.Println("e=", e)

5.数组比较与赋值

    //支持==,!=的比较,比较是不是每个元素都一样,2个数组比较,数组类型要相同
    a := [5]int{1, 2, 3, 4, 5}
	b := [5]int{1, 2, 3, 4, 5}
	c := [5]int{2, 2, 3, 4, 5}
	fmt.Println("a==b", a == b)
	fmt.Println("a==c", a == c)
    //同类型的数组可以赋值
	var d [5]int
	d = a
	fmt.Println("d=", d)

6.数组作函数参数

//数组作函数参数,它是值传递
//实参数组的每个元素给形参数组拷贝一份
//形参的数组是实参数组的复制品
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.数组指针作函数参数

//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)
}

三、随机数

1.随机数的使用

    //设置种子,只需要一次
    //如果种子参数一样,每次运行程序产生的随机数都一样
    rand.Seed(time.Now().UnixNano())//取当前的系统时间作为种子
	for i := 0; i < 5; i++ {
		fmt.Println("rand=", rand.Int())//不限制随机数的大小
		fmt.Println("rand=", rand.Intn(1000))//随机数大小限制在1000以内
	}

2.冒泡排序

func swap(a, b *int) {
	tmp := *a
	*a = *b
	*b = tmp
}
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)
		fmt.Printf("%d,", a[i])
	}
	fmt.Println()
    //冒泡排序,挨着2个元素比较,降序则交换
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-i-1; j++ {
			if a[j] > a[j+1] {
				//a[j],a[j+1]=a[j+1][j]
				swap(&a[j], &a[j+1])
			}
		}
	}
	for i, data := range a {
		fmt.Printf("a[%d]=%d\n", i, data)
	}
	fmt.Println()
}

四、切片

1.切片的长度和容量

    a := []int{1, 2, 3, 0, 0}//数组初始化
	s := a[0:3:5]//从0位置,截取长度为3,总容量为5
	fmt.Println("s=", s)
	fmt.Println("len(s)=", len(s))
	fmt.Println("cap(s)=", cap(s))
	s = a[1:4:5]
	fmt.Println("s=", s)
	fmt.Println("len(s)=", len(s))
	fmt.Println("cap(s)=", cap(s))

2.切片的创建

    s1 := []int{1, 2, 3, 4}
	fmt.Println("s1=", s1)
	s2 := make([]int, 5, 10)//借助make函数,格式make(slice,type,len,cap)
	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))

    //数组[]里面的长度是固定的一个常量,数组不能修改长度,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)//给切片末尾追加一个成员
	fmt.Printf("len%d,cap=%d\n", len(s), cap(s))

3.切片的截取

    array := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    //[low:high:max]取下标从low开始,len=high-low,cap=max-low
	s1 := array[:]//[0:len(array):len(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]
	fmt.Println("s2=", s2)
	fmt.Printf("len=%d,cap=%d\n", len(s2), cap(s2))
	s3 := array[:6]//从0开始,取6个元素,容量不是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))

4.切片与底层数组的关系

    a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	s1 := a[2:5]
	fmt.Println("s1=", s1)
	s1[1] = 666
	fmt.Println("s1=", s1)
	fmt.Println("a=", a)
	s2 := s1[2:7]
	s2[2] = 777
	fmt.Println("s2=", s2)
	fmt.Println("a=", a)

5.append函数的使用

s1 := []int{}
	fmt.Printf("len=%d,cap=%d\n", len(s1), cap(s1))
	fmt.Println("s1=", 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))
	s2 := []int{1, 2, 3}
	fmt.Println("s2=", s2)
	s2 = append(s2, 5)
	s2 = append(s2, 5)
	s2 = append(s2, 5)
	fmt.Println("s2=", s2)
	fmt.Printf("len=%d,cap=%d\n", len(s2), cap(s2))

6.append扩容特点

2倍扩容

    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
		}
	}

7.copy的使用

    srcSlice := []int{1, 2}
	dstSlice := []int{6, 6, 6, 6, 6}
	copy(dstSlice, srcSlice)
	fmt.Println("dstSlice=", dstSlice)

8.切片做函数参数

切片做参数,引用传递

//切片做参数,引用传递
func InitData(s []int) {
	rand.Seed(time.Now().UnixNano())//设置种子
	for i := 0; i < len(s); i++ {
		s[i] = rand.Intn(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] {
				swap(&s[j], &s[j+1])
			}
		}
	}
}
func swap(a, b *int) {
	tmp := *a
	*a = *b
	*b = tmp
}
func main() {
	var n int = 10
    //创建一个长度为n的切片
	s := make([]int, n)
	InitData(s)//初始化数组
	fmt.Println("排序前:", s)
	BubbleSort(s)//冒泡排序
	fmt.Println("排序后:", s)
}

9.猜数字游戏

func CreateNum(p *int) {//实参传递
	rand.Seed(time.Now().UnixNano())
	var num int
	for {
		num = rand.Intn(10000)
		if num > 1000 {
			*p = num
			break
		}
	}
}
func GetNum(randNum int, randSlice []int) {
	for i := 3; i >= 0; i-- {
		randSlice[i] = randNum % 10
		randNum /= 10
	}
}
func OnGame(randSlice []int) {
	var num int
	numSlice := make([]int, 4)
	for {
		fmt.Printf("请输入一个4位数:")
		fmt.Scan(&num)
		if num < 1000 || num > 9999 {
			fmt.Printf("输入不符合要求")
			continue
		} else {
			GetNum(num, numSlice)
		}
		fmt.Println("numSlice=", numSlice)
		n := 0
		for i := 0; i < 4; i++ {
			if randSlice[i] < numSlice[i] {
				fmt.Printf("第%d位大了一点", i+1)
			} else if randSlice[i] > numSlice[i] {
				fmt.Printf("第%d位小了一点", i+1)
			} else {
				fmt.Printf("第%d位猜对了", i+1)
				n++
			}
		}
		if n == 4 {
			fmt.Println("全部猜对")
			break
		}
	}
}
func main() {
	var randNum int
	CreateNum(&randNum)//产生一个4位随机数
	fmt.Println("randNum=", randNum)
	randSlice := make([]int, 4)
	GetNum(randNum, randSlice)//对4位数进行切片存储
	fmt.Println("randSlice=", randSlice)
	OnGame(randSlice)//猜数
}

五、map

1.map的基本使用

    //定义一个变量,类型为map[int]string
    var m1 map[int]string
	fmt.Println("m1=", m1)
    //map只有len,没有cap,可以通过make创建
	m2 := make(map[int]string)
	fmt.Println("m2=", m2)
	fmt.Println("len(m2)=", len(m2))
    //可以通过make,指定长度,只是指定了容量,但是里面确实一个数据也没有
	m3 := make(map[int]string, 10)
	m3[1] = "mike"
	m3[2] = "go"
	fmt.Println("m3=", m3)
    //map是无序的,无法决定它的返回顺序
	fmt.Printf("len(m3)=%d\n", len(m3))//2
    //键值是唯一的
	m4 := map[int]string{1: "mike", 2: "go", 3: "c"}
	fmt.Println("m4=", m4)

2.map的赋值

    m1 := map[int]string{1: "mike", 2: "yoyo"}
	fmt.Println("m1=", m1)
	m1[1] = "c++" //赋值
	fmt.Println("m1=", m1)
	m1[3] = "go" //追加,map底层会扩容,和append类似
	fmt.Println("m1=", m1)

3.map的遍历

    m := map[int]string{1: "mike", 2: "yoyo", 3: "go"}
//第一个返回值为key,第二个为value,遍历结果无序
	for key, value := range m {
		fmt.Printf("%d----->%s\n", key, value)
	}
//如何判断一个key值是否存在
//第一个返回值为key所对应的value,第二个返回值为key是否存在的条件
//存在ok为true,否则为false
	value, ok := m[0]
	if ok == true {
		fmt.Println("m[1]=", value)
	} else {
		fmt.Println("key不存在")
	}

4.map的删除

    m := map[int]string{1: "mike", 2: "yoyo", 3: "go"}
	fmt.Println("m=", m)
	delete(m, 1)//删除key为1的内容
	fmt.Println("m=", m)

5.map做函数参数

//实参引用
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)
	fmt.Println("m=", m)
}

六、结构体

1.结构体初始化

//定义一个结构体
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)
//指定成员初始化,没有初始化的成员,自动赋值为0
	s2 := Student{name: "mike", addr: "bj"}
	fmt.Println("s2=", s2)
}

2.结构体指针变量的初始化

type Student struct {
	id   int
	name string
	sex  byte
	age  int
	addr string
}
func main() {
	var p1 *Student = &Student{1, "mike", 'm', 18, "bj"}
	fmt.Println("*p1=", *p1)
	p2 := &Student{name: "mike", addr: "bj"}
	fmt.Printf("p2 type is %T\n", p2)//*main.Student
	fmt.Println("p2=", p2)
}

3.结构体成员的使用:普通成员

    var s Student
//操作成员需要.运算符
	s.id = 1
	s.name = "mike"
	s.sex = 'm'//字符
	s.age = 18
	s.addr = "bj"
	fmt.Println("s=", s)

4.结构体成员的使用:指针变量

    //1.指针有合法指向后,才操作成员
    //先定义一个普通结构体变量
    var s Student
    //在定义一个指针变量,保存s的地址
	var p1 *Student
	p1 = &s
    //通过指针操作成员,p1.id和(*p1).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)

5.结构体比较和赋值

    var s1 Student = 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)

6.结构体做函数参数

func test01(s Student) {
	s.id = 666
	fmt.Println("s=", s)
}
func main() {
	s := Student{1, "mke", 'm', 18, "bj"}
	test01(s)//值传递,形参无法改变实参
	fmt.Println("main", s)
}

func test02(s *Student) {
	s.id = 666
	fmt.Println("test:", s)
}
func main() {
	s := Student{1, "mike", 'm', 18, "bj"}
	test02(&s)
	fmt.Println("main", s)
}

七、go语言可见性规则

如果想使用别的包的函数、结构体、结构体成员

函数名,类型名,结构体成员变量名,首字母必须大写

可见,如果首字母小写,只能在同一个包里使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值