【2】go语言的学习之数组、切片、map和结构体

数组

1> 数组的定义

package main

import "fmt"

func main() {
	// 1、使用var关键字定义,需要指定数组的长度及数组元素的数据类型
	var arr1 [3]int
	// 2、使用 := 定义并指定长度,使用这种方法需要给数组初值
	arr2 := [3]int{1, 3, 5}
	/// 3、使用 := 定义不指定长度,同样要给初值
	arr3 := [...]int{2, 4, 6, 8}
	fmt.Println(arr1, arr2, arr3)
	//[0 0 0] [1 3 5] [2 4 6 8]

	// 定义一个2行3列的元素为int的二位数组
	var grid [2][3]int
	fmt.Println(grid)
	//[[0 0 0] [0 0 0]]
}

2> 数组的遍历

package main

import "fmt"

func main() {
	arr := [...]string{"a", "b", "c", "d", "e"}
	for k, v := range arr {
		// k为下标,v为值
		fmt.Println(k, v)
	}
	/*
		0 a
		1 b
		2 c
		3 d
		4 e
	*/
}

3> 数组是值类型
也就是说,在调用array的时候,会将其做一份拷贝,对拷贝后的array进行修改,并不会改变原来的值,同时这里又一次验证了在go语言中,函数参数的传递都是值传递

package main

import "fmt"

func printArry(arr [5]int) {
	arr[0] = 100
	fmt.Println("在printArry函数里")
	fmt.Println(arr)
}

func main() {
	arr := [...]int{1, 2, 3, 4, 5}
	printArry(arr)
	fmt.Println("在main里")
	fmt.Println(arr)
}

/*
在printArry函数里
[100 2 3 4 5]
在main里
[1 2 3 4 5]
*/

4> 冒泡排序

package main

import "fmt"

func main() {
	arr := [...]int{10, -2, -4, 6, 5}
	n := len(arr)
	// 外圈循环,根据数组长度控制比较的次数
	for i := 0; i < n-1; i++ {
		// 内圈循环,控制每次参与比较的两个元素
		for j := 0; j < n-1-i; j++ {
			if arr[j] > arr[j+1] {
				arr[j], arr[j+1] = arr[j+1], arr[j]
			}
		}
	}
	fmt.Println(arr)
}

在这里插入图片描述

切片

1> 切片不是值类型的,因为切片内部是有一个数据结构的
slice本身是没有数据的,是对底层array的一个view

package main

import "fmt"

func updata(slice []int) {
	slice[0] = 999
	fmt.Println(slice) // [999 3 4 5]
}

func main() {
	arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8}

	// 为什么说slice是array的view呢?
	// 比如说arr[2:6]
	// 它就记住说我们是要看arr的第2到第5个元素(半开半闭)
	fmt.Println("arr[2:6] = ", arr[2:6]) //arr[2:6] =  [2 3 4 5]
	// 所以此时这个slice里存的并不是值,而是arr里元素的引用,改变slice里的值,arr里的值会跟着改变
	s := arr[2:6]
	// 将切片下标为0的元素值改为999,arr的值跟着改变
	updata(s)
	fmt.Println(arr) // [0 1 999 3 4 5 6 7 8]
}

2> slice本身是没有数据的,是对底层array的一个view

package main

import "fmt"

func main() {
	arr := [...]string{"a", "b", "c", "d", "e", "f", "g", "h"}
	s1 := arr[2:6]
	fmt.Println(s1) // [c d e f]
	s2 := s1[3:5]
	fmt.Println(s2) // [f g]
}

在这里插入图片描述
数组arr为[…]int{0,1,2,3,4,5,6,7}
切片s1为[]int{2,3,4,5}
当切片s2对切片s1进行reslice的时候,取了s1的[3:5],此时切片s1最后一位下标为s1[3],但是切片s2并不会报错,因为slice是对arr的view
在这里插入图片描述
每个slice都有三个值,分别为

  • ptr:代表这个slice的开始位置
  • len:代表这个slice的长度
  • cap:代表这个slice的底层array的长度
  • s[i]不可以超越len(s),向后扩展不可以超越底层数组cap(s),不可以向前扩展
package main

import "fmt"

func main() {
	arr := [...]string{"a", "b", "c", "d", "e", "f", "g", "h"}
	s1 := arr[2:6]
	fmt.Printf("s1 = %v, len(s1) = %d, cap(s1) = %d\n", s1, len(s1), cap(s1))
	s2 := s1[3:5]
	fmt.Printf("s2 = %v, len(s2) = %d, cap(s2) = %d\n", s2, len(s2), cap(s2))
}

/*
s1 = [c d e f], len(s1) = 4, cap(s1) = 6
s2 = [f g], len(s2) = 2, cap(s2) = 3
*/

3> 向slice添加元素

package main

import "fmt"

func main() {
	arr := [...]int{1, 2, 3, 4, 5}
	// s1是对arr的一个view
	s1 := arr[2:4]
	// 此时s2仍是对arr的view,往s1的最后添加元素,也就是改变了arr下标为5的元素的值
	s2 := append(s1, 10)
	// 此时s3就不是对arr的view了,因为s3向后扩展已经超出了arr的下标,此时go分配了新的数组使s3来进行view
	s3 := append(s2, 11)
	fmt.Printf("s1 = %v, s2 = %v, s3 = %v\n", s1, s2, s3)
	fmt.Printf("arr = %v", arr)
}

/*
s1 = [3 4], s2 = [3 4 10], s3 = [3 4 10 11]
arr = [1 2 3 4 10]
*/
  • 添加元素时如果超越cap,系统会分配更大的底层数组,原来的数组如果有人用的话,就还存在,如果没人用,就会被自动垃圾回收掉
  • 由于值传递的关系,必须接受append的返回值

4> 创建切片

  1. 只声明slice: var s []int
  2. 声明slice并赋值: s := []int{2,4,6,8}
  3. 声明slcie不赋值但是指定长度为16:s := make([]int, 16)

5> 切片的拷贝

package main

import "fmt"

func main() {
	s1 := []int{1, 2, 3, 4}
	s2 := make([]int, 10)
	copy(s2, s1)
	fmt.Println(s2) // [1 2 3 4 0 0 0 0 0 0]
}

6> 切片的元素删除
go语言没有内建函数用来删除slice的元素,但是我们可以通过reslice来实现:比如说我们要删除s1中的元素4

package main

import "fmt"

func main() {
	s1 := []int{1, 2, 3, 4, 5, 6, 7}
	s2 := append(s1[:3], s1[4:]...)
	fmt.Println(s2)  // [1 2 3 5 6 7]
}

map

map做函数参数,是引用传递
1> map的创建

package main

import "fmt"

func main() {
	m1 := map[string]string{
		"name":   "lili",
		"sex":    "f",
		"school": "tinghua",
	}
	m2 := make(map[string]int)
	var m3 map[int]string
	fmt.Println(m1, m2, m3)
	//map[name:lili school:tinghua sex:f] map[] map[]
}

2> map的遍历

package main

import "fmt"

func main() {
	m1 := map[string]string{
		"name":   "lili",
		"sex":    "f",
		"school": "tinghua",
	}
	for k, v := range m1 {
		fmt.Println(k, v)
	}
}

/*
name lili
sex f
school tinghua
*/

3> 获取map里的item
获取map里的元素时,有两个返回值,一个为此key对应的值,一个为是否获取到,当此key不存在时,返回值为空,false

package main

import "fmt"

func main() {
	m1 := map[string]string{
		"name":   "lili",
		"sex":    "f",
		"school": "tinghua",
	}
	//获取map里已有的key对应的value
	name, ok := m1["name"]
	fmt.Println(name, ok) // lili true
	//获取map里没有的元素
	age, ok := m1["age"]
	fmt.Println(age, ok) //   false
}

4> 使用delete 删除map里的元素

package main

import "fmt"

func main() {
	m1 := map[string]string{
		"name":   "lili",
		"sex":    "f",
		"school": "tinghua",
	}
	name, ok := m1["name"]
	fmt.Println(name, ok) // lili true
	delete(m1, "name")
	name, ok = m1["name"]
	fmt.Println(name, ok) //   false
}

结构体

结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合。每个数据称为结构体的成员。
1> 结构体初始化

package main

import "fmt"

type student struct {
	name string
	age  int
	sex  byte
	addr string
}

func main() {
	// 顺序初始化,每个成员都必须初始化
	var s1 student = student{"coco", 18, 'f', "bj"}
	fmt.Println(s1) // {coco 18 102 bj}

	// 指定初始化,没有初始化的成员为零值
	s2 := student{name: "lili", age: 20}
	fmt.Println(s2) // {lili 0 0 sh}

	//通过成员初始化
	var s3 student
	s3.name = "coco"
	s3.addr = "bj"
	fmt.Println(s3)  // {coco 0 0 bj}

2> 结构体做函数参数
结构体做函数参数,为值传递

package main

import "fmt"

type student struct {
	name string
	age  int
	sex  byte
	addr string
}

func updata(s student) {
	s.name = "lili"
	fmt.Println("updata func : ", s) // updata func :  {lili 18 102 sh}
}

func main() {
	s := student{"coco", 18, 'f', "sh"}
	updata(s)
	fmt.Println("main func : ", s) // main func :  {coco 18 102 sh}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值