首页 > 其他分享 >学相伴—Go语言切片与Map

学相伴—Go语言切片与Map

时间:2022-12-20 23:23:21浏览次数:32  
标签:Map s1 cap len 切片 Println Go fmt

切片Slice

Go语言切片是对数组的抽象

Go数组的长度不可改变,在特定场景这样的集合就不太适用,Go提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数组相比切片的长度是不固定的可以追加元素,在追加时可能使切片的容量增大

切片是一种方便、灵活且强大的包装器,切片本身没有任何数据,他们只是对现有数组的引用

切片与数组相比,不需要设定长度,在[]中不用设定值,相对来说比较自由

从概念上面来说slice像一个结构体,这个结构体包括三个元素:

  • 指针:指向数组中slice指定的开始位置
  • 长度:即slice的长度
  • 最大长度:也就是slice开始位置到数组最后位置的长度

定义切片

package main

import "fmt"

func main() {
   // 数组长度一旦确定就不可改变
   arr := [5]int{1, 2, 3, 4, 5}
   fmt.Println(arr)

   // 定义切片
   var s1 []int
   fmt.Println(s1)
   if s1 == nil {
      fmt.Println("切片为空")
   }

   s2 := []int{1, 2, 3} //切片 变长
   fmt.Println(s2)
   fmt.Printf("%T%T\t%T", s1, s2, arr)
}
/*
结果:
[1 2 3 4 5]
[]
切片为空
[1 2 3]
[]int[]int      [5]int
*/

make函数创建切片

使用make()函数来创建切片

make([]T,length,capactity)

切片是可索引的,并且可以由len()方法来获取长度

切片提供了计算容量的方法cap()可以测量切片最长可以到达多少

package main

import "fmt"

func main() {
   // 用make函数创建切片
   s1 := make([]int, 5, 10)
   fmt.Println(s1)
   fmt.Println(len(s1)) //长度:5
   fmt.Println(cap(s1)) //容量:10

   s1[0] = 100 //给元素进行赋值
   //s1[6] = 20 //index out of range [6] with length 5
   fmt.Println(s1)
}
/*
[0 0 0 0 0]
5
10
[100 0 0 0 0]
*/

切片扩容和遍历

package main

import "fmt"

func main() {
   s1 := make([]int, 0, 5)
   s1 = append(s1, 1, 2, 3)
   fmt.Println(s1)
   //如果切片中的数据超过了规定的容量,那么他就会自动扩容
   s1 = append(s1, 4, 5, 6, 7, 8, 9)
   fmt.Println(s1)

   s2 := []int{1, 1, 1, 1, 1}
   s1 = append(s1, s2...) //将s2的数据添加到s1里面  s2...可以理解为结构体 目的将s2里面的数据解析出来
   fmt.Println(s1)

   //循环遍历输出切片的数据
   for i := 0; i < len(s1); i++ {
      fmt.Println(s1[i])
   }
   //range遍历
   for _, i := range s1 { //_,i  将打印下标去掉 只打印输出值
      fmt.Println(i)
   }
}
/*
[1 2 3]
[1 2 3 4 5 6 7 8 9]
[1 2 3 4 5 6 7 8 9 1 1 1 1 1]
1
2
3
4
5
6
7
8
9
1
1
1
1
1
1
2
3
4
5
6
7
8
9
1
1
1
1
1

*/

扩容的内存分析

package main

import "fmt"

func main() {

   s1 := []int{1, 2, 3}
   fmt.Println(s1)
   fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
   fmt.Printf("地址:%p\n", s1)

   s1 = append(s1, 4, 5)
   fmt.Println(s1)
   fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
   fmt.Printf("地址:%p\n", s1)

   s1 = append(s1, 6, 7)
   fmt.Println(s1)
   fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
   fmt.Printf("地址:%p\n", s1)

   s1 = append(s1, 8, 9, 10)
   fmt.Println(s1)
   fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
   fmt.Printf("地址:%p\n", s1)
}
/*
[1 2 3]
长度len:3,容量cap:3
地址:0xc0000aa078
[1 2 3 4 5]
长度len:5,容量cap:6
地址:0xc0000c8030
[1 2 3 4 5 6 7]
长度len:7,容量cap:12
地址:0xc000086060
[1 2 3 4 5 6 7 8 9 10]
长度len:10,容量cap:12
地址:0xc000086060
*/
  • 每一个切片引用了一个底层数组
  • 切片本身不存储任何数据,都是这个底层数组存储,所以修改切片也就是修改这个数组的数据
  • 当向切片中添加数据时,如果没有超过容量,直接添加,若果超过容量,自动扩容,成倍增加
  • 切片一旦扩容,就会重新指向一个新的底层数组

在已有数组上创建切片

从已有的数组上,直接创建切片,该切片的底层数组就是当前的数组,长度是从start到end切到的数据量,但是容量从start到数组的末尾

slice := arr[start:end]

package main

import "fmt"

func main() {
	//定义一个数组
	arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	s1 := arr[:5]  //切片从1-5 [1 2 3 4 5]
	s2 := arr[4:8] //[5 6 7 8]
	s3 := arr[5:]  //[6 7 8 9 10]
	s4 := arr[:]   //[1 2 3 4 5 6 7 8 9 10]
	fmt.Println(s1)
	fmt.Println(s2)
	fmt.Println(s3)
	fmt.Println(s4)

	fmt.Printf("长度len:%d,容量cap:%d\n", len(s1), cap(s1))
	fmt.Printf("长度len:%d,容量cap:%d\n", len(s2), cap(s2))
	fmt.Printf("长度len:%d,容量cap:%d\n", len(s3), cap(s3))
	fmt.Printf("长度len:%d,容量cap:%d\n", len(s4), cap(s4))

	arr[0] = 100 //将数组元素值进行更换
	fmt.Println(arr)
	fmt.Println(s1)

	s1[1] = 100 
	fmt.Println(arr)
	fmt.Println(s1)

	fmt.Printf("%p\n", s1)
	fmt.Printf("%p\n", &arr)
}
/*
[1 2 3 4 5]
[5 6 7 8]
[6 7 8 9 10]
[1 2 3 4 5 6 7 8 9 10]
长度len:5,容量cap:10
长度len:4,容量cap:6
长度len:5,容量cap:5
长度len:10,容量cap:10
[100 2 3 4 5 6 7 8 9 10]
[100 2 3 4 5]
[100 100 3 4 5 6 7 8 9 10]
[100 100 3 4 5]
0xc0000ac0f0
0xc0000ac0f0
*/

切片是引用类型

package main

import "fmt"

func main() {
   //数组:值传递
   arr1 := [4]int{1, 2, 3, 4}
   arr2 := arr1
   arr2[0] = 100
   fmt.Println(arr1, arr2)

   //切片:引用类型
   s1 := []int{1, 2, 3, 4}
   s2 := s1
   //切片2里元素发生变化,切片1也会跟随着变化
   s2[0] = 200
   fmt.Println(s1, s2) 
   //说明切片的copy指向的是地址
   fmt.Printf("%p,%p", s1, s2)
}
/*
[1 2 3 4] [100 2 3 4]
[200 2 3 4] [200 2 3 4]
0xc000012260,0xc000012260

*/

深拷贝与浅拷贝

深拷贝:拷贝的是数据本身

  • 值类型的数据,默认都是深拷贝: array、int、float、string.bool、sturct
  • 浅拷贝:拷贝的是数据的地址,会导致多个变量指向同一块内存
  • 引用类型的数据,默认都是浅拷贝: slice、map
  • 因为切片是引用类型的数据,直接拷贝的是地址
package main

import "fmt"

func main() {
   s1 := []int{1, 2, 3, 4}
   s2 := make([]int, 0, 0)
   for i := 0; i < len(s1); i++ {
      s2 = append(s2, s1[i]) //将s1里的元素一个一个追加到s2里面
   }
   fmt.Println(s1)
   fmt.Println(s2)

   //切片深拷贝
   s2[0] = 100
   fmt.Println(s1)
   fmt.Println(s2)
   fmt.Printf("%p,%p", s1, s2)

   // copy
   s3 := []int{5, 6, 7, 8}
   fmt.Println(s1, s3)

   copy(s1, s3) //(接收者,传递者)
   fmt.Println(s1, s3)
   fmt.Printf("%p,%p", s1, s3)
}

标签:Map,s1,cap,len,切片,Println,Go,fmt
From: https://www.cnblogs.com/DuPengBG/p/16992070.html

相关文章

  • MyBatis good
    增加下面的配置,就会把spring-mybatis中debug的日志也打印出来mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImplCreatinganewSqlSessionSqlS......
  • g2o相关问题cs.h,以及no matching function for call to ‘g2o::OptimizationAlgorith
    1.对于cs.h找不到的情况1)编译的时候一定要把csparse在EXTERNAL文件中,编译进去。2)修改CMakeLists.txt文件中的include_directories中的${CPARSE_INCLUDE_DIR},在DIR后面不能加......
  • Django框架8
    今日内容概要ajax补充说明多对多三种创建方式django内置序列化组件ORM批量操作数据自定义分页器form组件今日内容详细ajax补充说明主要是针对回调函数args接收......
  • django模型层之models入门篇(Relationship fields)
    先看下models结构:#tournament/models.pyfromdjango.dbimportmodelsclassClub(models.Model):region_choices=[('E','East'),('W','W......
  • django10 分页器与Form组件
    多对多创建第三张表的三种方式#1.全自动创建#优势:自动创建第三张表,并且提供了add,remove,set,clear四种操作与正反向查询#劣势:第三张表无法创建更多的字段,扩展性很......
  • djangoday09
    目录9django一、ajax补充说明二、多对多三种创建方式三、django内置序列化组件(drf前身)四、ORM批量操作数据(ORM操作优化)五、自定义分页器六、form组件9django一、ajax......
  • 多对多三种创建方式、django内置序列化组件
    内容概要ajax补充说明多对多三种创建方式django内置序列化组件(drf前身)ORM批量操作数据(ORM操作优化)自定义分页器form组件内容详细ajax补充说明主要是针......
  • ajax补充知识点、多对多外键的三种创建方式、django内置序列化组件、批量操作数据、分
    今日内容ajax补充说明主要是针对回调函数args接收到的响应数据1.后端request.is_ajax() 用于判断当前请求是否由ajax发出2.后端返回的三板斧都会被args接收不在影......
  • django相关操作
    Django内置序列化组件我们在学习Django内置序列化组件之前需要知道的一点是:前后端分离的项目,它的视图函数只需要返回json格式的数据即可fromdjango.httpimportJsonRe......
  • Django9
    Ajax补充说明主要针对回调函数args接收到后端的响应数据1.后端request.is_ajax()后端用于判断当前用户的请求是否由Ajax发出结果:还可以再细分2.后端返回的三板斧......