首页 > 其他分享 >Go04-数组+切片+map

Go04-数组+切片+map

时间:2024-03-18 17:37:46浏览次数:22  
标签:map a1 int Go04 切片 a2 Println fmt

Go4-数组+切片+map

1.数组的定义、赋值、访问和遍历

// 1 数组用来存放多个同一类型的数据,在Go中数组是值类型。
// 2 数组的定义、赋值和遍历。
// 定义数字。
var arrs [2]int
// 给数组元素赋值。
arrs[0] = 0
arrs[1] = 2

// 0 2
for i := 0; i < len(arrs); i++ {
    fmt.Println(arrs[i])
}

// 0 = 2 ; 1 = 2
for index, value := range arrs {
    fmt.Println(index, "=", value)
}

// 3 通过地址访问数据中的元素。
var a2 [2]int
a2[0] = 1
a2[1] = 2
// // 3.1 数组的地址就是数组第一个元素的地址。
// 数组的地址0xc00000a0d0,数组第一个元素的地址0xc00000a0d0
fmt.Printf("数组的地址%p,数组第一个元素的地址%p\n", &a2, &a2[0])
// 3.2 通过数组地址的指向获取数组的值。
// 0xc00000a0d8 2
fmt.Println(&a2[1], *&a2[1])

// 4 四种初始化数组的方式。
// 4.1 初始化数组的方式一。
var a3 [3]int = [3]int{1, 2, 3}
fmt.Println(a3) // [1 2 3]

// 4.2 初始化数组的方式二。
var a4 = [3]int{1, 2, 3}
fmt.Println(a4) // [1 2 3]

// 4.3 初始化数组的方式三。
// 这里的[...]是规定的写法。
var a5 = [...]int{1, 3, 5}
fmt.Println(a5) // [1 3 5]

// 4.4 初始化数组的方式四,按照索引初始化数据。
var a6 = [...]int{1: 100, 0: 10, 2: 1000}
fmt.Println(a6) // [10 100 1000]

// 4.5 初始化数组的方式五。
a7 := [...]string{1:"3", 0:"1", 2:"5"}
fmt.Println(a7)

// 5 数组for...range遍历。
// 5.1 for...range遍历不忽略索引。
a8 := [...]int{1, 10}
// 0 1; 1 10;
for index, value := range a8 {
    fmt.Println(index, value, ";")
}

// 5.2 for...range遍历使用_忽略索引。
// 1 10
for _, value := range a8 {
    fmt.Println(value)
}

// 5.3 for...range变量时,如果只有一个返回值,则返回的是索引。
// 0 1
for index := range a8 {
    fmt.Println(index)
}

2.数组的注意事项和使用细节

func main() {
	// 1 数组一旦定义了长度就不能改变了;
	// 数组一旦定义了存储的数据类型就只能存储是定义的类型。

	// 2 数组定义之后没有赋值就是默认值。
	//数值(整数和浮点型)默认值为0,字符串默认值为""空串, bool默认值为false。
	var a1 [3]int
	fmt.Println(a1) // [0 0 0]

	// 3 数组的下标必须在指定范围之内,否则报错。
	// 报错:invalid argument: array index 3 out of bounds [0:3]
	// a1[3] = 1

	// 4 Go中数组属于值类型,默认情况下是指传递,会进行值拷贝。
	// 函数之间数组传递之后的修改不会影响原数组的值。
	a2 := [...]int{1, 3, 5}
	fmt.Println(1, a2) // 1 [1 3 5]
	test01(a2)
	fmt.Println(3, a2) // 3 [1 3 5]

	// 5 数组默认是值传递,如果在函数传递时想修改数组的值,可以使用指针进行引用传递。
	a3 := [...]int{2, 4, 6}
	fmt.Println(1, a3) // 1 [2 4 6]
	test02(&a3)
	fmt.Println(3, a3) // 3 [2 100 10]

	// 6 使用byte数组保存A-Z,然后输出打印。
	var a4 [26]byte
	for i := 0; i < 26; i++ {
		a4[i] = 'A' + byte(i)
	}

	// [A B C D E F G H I J K L M N O P Q R S T U V W X Y Z]
	fmt.Printf("%c", a4)
}

func test02(a *[3]int)  {
	// 两种通过指针修改数组值的方式,推荐使用第二种,容易理解。
	// 不推荐使用这种方式修改数组的值。
	*(&(a[2])) = 10
	// *a取数组a的首地址,(*a)[1]然后偏移1位。
	(*a)[1] = 100
	fmt.Println(a) // &[2 100 10]
}

func test01(a [3]int)  {
	a[0] = 10
	fmt.Println(2, a) // 2 [10 3 5]
}

3.切片的创建和遍历

// 1 切片相当于动态数组,在数组的长度不确定时就可以使用切片来定义数组。
// 2 切片是数组的一个引用,因此切片是引用类型。
// 3 切片的定义语法。var 切片名 []类型

var a1 [5]int = [5]int{1, 3, 5, 7, 8}
var a2 []int = a1[1 : 3]
// 切片 [3 5]
fmt.Println("切片", a2)
// 切片元素的个数 2
fmt.Println("切片元素的个数", len(a2))
// 切片的容量 4
fmt.Println("切片的容量", cap(a2))

// 4 从底层上来讲切片就是一个结构体。
/*
	type slice struct {
		ptr *[2]int // 保存数据的首地址。
		len int // 保存数组中元素的个数。
		cap int // 保存切片的容量。
	}
	 */

// 5 切片的三种创建使用。
// 5.1 切片的创建方式一,通过数组来创建切片。
var a3 [5]int = [5]int{1, 10, 100, 1000, 10000}
// 取数组的索引1和索引2处的值,1:3,表示1-3,但是不包含3。
var a4 []int = a3[1:3]
fmt.Println(a4) // [10 100]

// 5.2 切片的创建方式二,使用make来创建切片。
// 语法 var 切片名 []type = make([]type, len, [cap])
// type是要创建的切片的类型;len切片的大小;cap是切片的容量,可选,如果设置了cap,则需要cap大于等于len。
var a5 []float64 = make([]float64, 5, 10)
fmt.Println(len(a5), cap(a5)) // 5 10

var a6 []float64 = make([]float64, 5)
fmt.Println(len(a6), cap(a6)) // 5 5

// 5.3 切片的创建方式三,直接初始化切片。
var a7 []int64 = []int64{1, 2, 3, 5, 7}
fmt.Println(a7) // [1 2 3 5 7]
fmt.Println(len(a7), cap(a7)) // 5 5

// 5.4 引用数组创建切片和make创建切片的区别。
// 引用数组创建切片,数组是存在的,这个数组对程序员来说是可见的。
// 通过make创建切片,make会先创建一个数组,这个数组由切片维护,数组对程序员来说是不可见的。

// 6 切片的两种遍历方式。
a8 := []int{1, 2, 3}
// 常规for循环遍历。
// 1 2 3
for i := 0; i < len(a8); i++ {
    fmt.Println(a8[i])
}

// for...range遍历切片。
// 0 1 ; 1 2 ; 2 3 ;
for index, value := range a8 {
    fmt.Println(index, value, ";")
}

4.切片的使用细节和常用函数

func main() {
	// 1 切片在初始化时,不能超过数组的长度,范围在0-len(arr)之间,
	// 但是切片长度可以动态增长。
	var a1 [3]int = [3]int{1, 2, 3}
	var a2 []int = a1[0 : len(a1)]
	fmt.Println(a2) // [1 2 3]

	// 2 创建切片的简写方式。
	// var a3 []int = a1[0, end]的简写。
	var a3 []int = a1[:1]
	fmt.Println(a3) // [1]

	// var a4 []int = a1[start: len(a1)]的简写。
	var a4 []int = a1[1:]
	fmt.Println(a4) // [2 3]

	// var a5 []int = a1[0 : len(a1)]的简写。
	var a5 []int = a1[:]
	fmt.Println(a5) // [1 2 3]

	// 3 对切片的切割。
	a6 := [...]int{1, 2, 3, 4, 5}
	a7 := a6[:]
	a8 := a7[1:2]
	fmt.Println(a7, a8) // [1 2 3 4 5] [2]
	
	// 4 append()内置函数,对切片进行动态追加。
	var a9 []int = []int{1}
	fmt.Println(a9) // 1
	a9 = append(a9, 10, 20)
	fmt.Println(a9) // [1 10 20]

	a10 := []int{-1, -2}
	// append()如果追加的是一个切片,则需要将切片解构为元素。
	// a10...,将切片解构为数组。
	a9 = append(a9, a10...)
	// [1 10 20 -1 -2]
	fmt.Println(a9)

	// 5 copy()内置函数,进行切片数据的拷贝。
	a11 := []int{1, 2}
	var a12 []int = make([]int, 5)
	fmt.Println(a12) //
	copy(a12, a11)
	fmt.Println(a12) // [1 2 0 0 0]

	// 将len()大的切片拷贝给len()小的切片。
	var a13 = make([]int, 1)
	copy(a13, a11)
	fmt.Println(a13) // [1]

	// 6 切片是引用类型,在传递时遵循引用类型的传递机制。
	a14 := [...]int{1, 10, 100}
	a15 := a14[:]
	a16 := a15
	a16[0] = -1
	fmt.Println(a16) // [-1 10 100]
	fmt.Println(a14) // [-1 10 100]
	fmt.Println(a15) // [-1 10 100]

	a17 := []int{1, 2}
	fmt.Println(a17) // [1 2]
	test01(a17)
	fmt.Println(a17) // [-10 2]
}

func test01(a []int) {
	a[0] = -10
}

5.string和slice

// 1 string底层是一个byte数组,因此string也可以进行切片的操作。
a1 := "hello张三"
a2 := a1[1:5]
fmt.Println(a2) // ello

// 使用数组切片时需要注意汉字占用了三个字节。
a3 := a1[1:6]
fmt.Println(a3) // ello�

a4 := a1[1:8]
fmt.Println(a4) // ello张

// 2 string类型是不可变的,所以不能通过a[0] = 'a'修改字符串。
a5 := "hello"
fmt.Println(a5) // hello
// 报错:cannot assign to a5[0] (value of type byte)
// a5[0] = "n"

// 3 如果需要修改字符串,则可以将字符串转[]byte或者[]rune,修改之后在转换为字符串。
// 3.1 将字符串转换为[]byte,修改在转换为字符串。
// 转换为[]byte不能用于中文的修改, 因为[]byte按照字节处理,一个中文占用三个字节。
// 对于[]byte不能处理中文修改的问题,可以将字符串转换为[]rune来处理。
a6 := "hello"
var a7 []byte = []byte(a6)
a7[0] = 'a'
a6 = string(a7)
fmt.Println(a6) // aello

// 3.2 将字符串转换为[]rune来解决修改中文乱码问题。
a8 := "h张三"
a9 := []rune(a8)
a9[1] = '李'
a9[2] = '1'
a8 = string(a9)
fmt.Println(a8) // h李1

6.二维数组

// 1 二维数组的使用方式一,先声明定义,在赋值。
var a1 [2][3]int
a1[0][0] = 1
a1[0][1] = 2
a1[0][2] = 3

a1[1][0] = 4
a1[1][1] = 5
a1[1][2] = 6
fmt.Println(a1) // [[1 2 3] [4 5 6]]

// 2 二维数组的使用方式二,直接初始化。
var a2 [2][3]int = [2][3]int{{1, 10, 100}, {1, 2, 3}}
fmt.Println(a2) // [[1 10 100] [1 2 3]]

// 3 二维数组声明定义的方式三。
var a3 = [...][2]int{{2, 4}, {1, 3}}
fmt.Println(a3) // [[2 4] [1 3]]

// 4 二维数组的遍历。
// 4.1 二维数组传统的方式遍历。
var a4 = [...][2]int{{2, 4}, {1, 3}}
/*
		2 4
		1 3
	 */
for i := 0; i < len(a4); i++ {
    for j := 0; j < len(a4[i]); j++ {
        fmt.Printf("%d\t", a4[i][j])
    }
    fmt.Println()
}

// 4.2 for...range遍历二维数组。
/*
		2 4
		1 3
	*/
for _, v1 := range a4 {
    for _, v2 := range v1 {
        fmt.Printf("%d\t", v2)
    }
    fmt.Println()
}

7.map初始化和赋值

// 1 map的key可以是bool、int、float、string、指针、channel、接口、结构体和数组;
// 但是map的key不能是slice、map和function,因为这三种类型无法进行==判断;
// 通常map的key为int、string类型。

// 2 map中value的类型和key的类型一致,可以是bool、int、float、string、map、指针、
// channel、接口、结构体和数组;通常为int、float、string、map和struct。

// 3 map的声明语法,var 变量名 map[keyType]valueType;
// 声明一个map是不会分配内存的,只有使用make初始化后才会分配内存;
// 分配内存后才能赋值和使用。

// 3.1 声明一个map
var a1 map[int]string
// 3.2 使用make初始化map会给map分配内存,map在使用前必须使用make分配内存。
a1 = make(map[int]string, 1)
a1[1] = "tom"
a1[2] = "alice"
fmt.Println(a1) // map[1:tom 2:alice]

// 3.3 声明的map的value类型是map
var a2 map[string]map[int]string
a2 = make(map[string]map[int]string, 1)
a2["one"] = a1
fmt.Println(a2) // map[one:map[1:tom 2:alice]]

// 4 map的使用。
// 4.1 map的第一种使用方式。
var a3 map[int]string
a3 = make(map[int]string, 1)
a3[1] = "a1"
a3[2] = "a2"
fmt.Println(a3) //

// 4.2 map的第二种使用方式。
a4 := make(map[string]int)
a4["one"] = 1
a4["two"] = 2
fmt.Println(a4) // map[one:1 two:2]

// 4.3 map的第三种使用方式。
a5 := map[string]string {
    "1": "tom",
    "2": "alice",
}
a5["3"] = "bob"
fmt.Println(a5) // map[1:tom 2:alice 3:bob]

8.map的增删改查操作

// 1 map的增加和更新,如果map中没有key则是增加操作;如果map中有key则是更新操作。
a1 := make(map[string]string, 10)
a1["a"] = "alice" // 增加
a1["b"] = "bob" // 增加
a1["a"] = "tom" // 更新
fmt.Println(a1) // map[a:tom b:bob]

// 2 map的删除需要使用内置函数delete。delete函数需要传入map和要删除的key。
// 如果这个key存在则删除当前key;如果key不存在,不进行操作,也不会报错。
// 3 删除map中key的两种方式:遍历map的key,逐个删除;
// 将当前map设置为空,等待垃圾回收,如a2 = nil。
a2 := make(map[string]string)
a2["1"] = "a1"
a2["2"] = "a2"

fmt.Println(a2) // map[1:a1 2:a2]

// delete删除map的key。
delete(a2, "2")
fmt.Println(a2) // map[1:a1]
// 删除不存的key不会报错。
delete(a2, "3")

// 3 map的查找。map的查找会返回两个参数,查找的值和bool类型的是否查找到。
// 如果找到则返回查找到的值和true;如果没有找到则返回value类型的默认值和false。
a3 := make(map[string]int, 1)
a3["a1"] = 1
a3["a2"] = 2
a3["a3"] = 3
i, ok := a3["a2"]
// 查找到了
if ok {
    fmt.Println("查找到了")
}
fmt.Println(i, ok) // 2 true
i, ok = a3["a4"]
fmt.Println(i, ok) // 0 false

// 4 map的遍历。
a4 := make(map[string]string)
a4["1"] = "a1"
a4["2"] = "a2"
// 2 a2 == 1 a1
for key, value := range a4 {
    fmt.Println(key, value)
}

// 5 计算map的长度。使用内置函数len()计算map的长度。
a5 := make(map[string]string)
a5["1"] = "a1"
a5["2"] = "a2"
fmt.Println(len(a5)) // 2

9.map的其他操作

  1. map切片。
// 1 切片的类型如果是map,则成为slice of map,map切片,这样map的个数就可以动态变化了。

// 2 声明map切片。
var a1 []map[string]int
a1 = make([]map[string]int, 2)

// 给a1[0]分配空间,并进行初始化。
a1[0] = make(map[string]int, 1)
a1[0]["tom"] = 1

// 给a1[1]分配空间,并进行初始化。
a1[1] = make(map[string]int, 1)
a1[1]["alice"] = 2

// 给a1[2]分配空间,并进行初始化。
// 此时会报错:panic: runtime error: index out of range [2] with length 2
// 因为map切片的长度是2,如果想动态扩容,可以使用切片的append()函数。
// a1[2] = make(map[string]int, 1)
// a1[2]["tom"] = 1
map1 := map[string]int {
    "tom": 1,
}
fmt.Println(a1) // [map[tom:1] map[alice:2]]
a1 = append(a1, map1)
fmt.Println(a1) // [map[tom:1] map[alice:2] map[tom:1]]
  1. map排序。
// 1 map默认是无序的,map的输出不会按照添加顺序输出。
a1 := map[int]int {
    10: 100,
    1: 10,
    4: 20,
    8: 30,
}
fmt.Println(a1) // map[1:10 4:20 8:30 10:100]
fmt.Println(a1) // map[1:10 4:20 8:30 10:100]

// 2 如果想按照map的key顺序输出key,则需要先key放入到切片中,然后对切片进行排序,
// 最后遍历切片,按照key输出map的值。
a2 := map[int]int {
    10: 100,
    1: 10,
    4: 20,
    8: 30,
}
// 将map的key放入切片中。
var a3 []int
for key, _ := range a2 {
    a3 = append(a3, key)
}
// 对切片进行排序。
sort.Ints(a3)
// 遍历切片。
// 10 20 30 100
for _, value := range a3 {
    fmt.Println(a2[value])
}
  1. map的使用细节。
// 1 向map中增加元素时,当超过map的容量后,会触发map的自动扩容,
// 不会发生panic,即map可以动态增长。

// 2 map获取数据。当map的value是一个map时,如果没有查找到可以通过nil判断,
// 即引用类型的默认值为nil。
a1 := make(map[string]map[string]int, 2)
a2 := a1["a1"]
fmt.Println(a2) // map[]

// a2 == nil
if a2 == nil {
    fmt.Println("a2 == nil")
}

a3 := make(map[string]string)
a4 := a3["a1"]
fmt.Println(a4)
// 当map的value是值类型时,不能通过nil判断是否为空,否则报错。
// 报错:invalid operation: a4 == nil (mismatched types string and untyped nil)
/*
	if a4 == nil {
		fmt.Println()
	}
*/

标签:map,a1,int,Go04,切片,a2,Println,fmt
From: https://www.cnblogs.com/godistance/p/17258514.html

相关文章

  • 【STL】 C++常用容器介绍系列(一)----(map、set、stack)
    目录一、map系列1、map介绍2、unordered_map介绍3、map和unordered_map的选择二、set系列1、set介绍2、unordered_set介绍3、set和unordered_set的选择三、如何遍历和查询map和set1、map的遍历2、map的查询3、set的遍历4、set的查询四、stack介绍和操作stack的方......
  • 实现 React-redux(一) connect 和 mapStateToProps
    1.结合context和storeimportReact,{Component}from'react';importPropTypesfrom'prop-types'functioncreateStore(reducer){letstate=nullconstlisteners=[]constsubscribe=(listener)=>listeners.push(listener)con......
  • 实现 React-redux(二) mapDispatchToProps
     App.js:importReact,{Component}from'react';importPropTypesfrom'prop-types'importHeaderfrom'./Header'functioncreateStore(reducer){letstate=nullconstlisteners=[]constsubscribe=(listener)=>l......
  • 学习JavaEE的日子 Day27 手撕HashMap底层原理
    Day271.手撕HashMap底层原理(重点)publicclassTest01{ publicstaticvoidmain(String[]args){ // Floatfloat1=newFloat("0.0f");// Floatfloat2=newFloat("0.0f");// Floatresult=float1/float2;// System.out.println(result);/......
  • 【Java】List, Set, Queue, Map 区别?
    目录List,Set,Queue,Map区别?Collection和CollectionsListArrayList和Array区别?ArrayList与LinkedList区别?ArrayList能添加null吗?ArrayList插入和删除时间复杂度?LinkedList插入和删除时间复杂度?LinkedList为什么不能实现RandomAccess接口?SetComparabl......
  • Python疑难杂症(13)---Python的几个比较难理解的内置函数,包括range、zip、map、lambda
    1、range()range(start=0, stop[, step=1])构造器的参数必须为整数(可以是内置的 int 或任何实现了 __index__() 特殊方法的对象)。生成一个start到stop的数组,左闭右开, 类型表示不可变的数字序列,通常用于在 for 循环中循环指定的次数。list(range(6))[0,1,2,3......
  • sqlmap入门教程,对注入点进行自动化注入(入门版)
    1.sqlmap介绍sqlmap是一款开源的渗透测试工具,可以自动化进行SQL注入的检测、利用。下载地址:GitHub-sqlmapproject/sqlmap:AutomaticSQLinjectionanddatabasetakeovertoolsqlmap在kali中打开命令行直接使用即可。2.使用sqlmap自动化检测sql注入点  打开kali,......
  • C++示例:学习C++标准库,std::unordered_map无序关联容器的使用
    01std::unordered_map介绍std::unordered_map是C++标准库中的一种无序关联容器模板类,它提供了一种将键映射到值的方法。它的底层基于哈希表实现,内容是无序的,可以在平均情况下在O(1)的时间复杂度内完成插入、查找和删除操作。值得注意的是,哈希表可能存在冲突,即不同的键值......
  • Android混淆后的bug日志通过mapping文件找对应行号
    背景由于项目中提测以及线上的apk都是经过混淆处理的,因此拿到日志后也无法正常查看崩溃日志的行号这个原因是因为混淆了文件,输出的日志是对应不上源文件的,为了正确找到行号需要用到mapping.txt文件配置开启保留行号和源文件要想利用mapping文件找到对应的行号,则还需要在混淆......
  • map/multimap容器
    map/multimap容器1.map基本概念简介:map中所有元素都是pairpair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)所有元素都会根据元素的键值自动排序对于map的底层原理,是通过红黑树(一种非严格意义上的平衡二叉树)来实现的,因此map内部所有的数据都是有序的m......