3.9 Go Slice切片

  1. Go语言切片(Slice)
  2. 切片是可动态变化的序列,是对数组的引用引用类型,遵循引用传递的机制
  3. slice类型写作[ ]T,T是slice元素类型,var s1 []int,s1就是切片变量
package main

import "fmt"

func main() {
//创建一个数组
var array1 [5]int = [...]int{11, 22, 33, 44, 55}
/*
创建切片,通过对数组的索引切片
s1 是切片名
array1[1:3]代表slice引用数组区间,索引1到索引3的值,注意取头不取尾,
*/
s1 := array1[1:4]
fmt.Println(array1)
fmt.Println(s1)
fmt.Println(len(s1))
fmt.Println(cap(s1))
}

运行结果

[11 22 33 44 55]     //原本数组
[22 33 44] //切片的值
3 //切片元素长度
4 //切片容量

2. 切片原理

slice是一个轻量级数据结构,提供访问数组子序列元素的功能。

slice由三个部分构成,指针、长度、容量

指针:指针指向slice第一个元素对应的数组元素的地址。

长度:slice元素的数量,不得超过容量。

容量:slice开始的位置到底层数据的结尾

package main

import "fmt"

func main() {
//创建数组,Months月份,1月份到12月份
months:=[...]string{"","January","February","March","April","May","June","July","August","September","October","November","December"}
//创建切片,对数组的引用
s1:=months[4:7]//[April May June]
s2:=months[6:9]//[June July August]
fmt.Println(s1)
fmt.Println(s2) //指针:指针指向slice`第一个元素`对应的`数组元素`的地址。
fmt.Printf("slice第一个元素地址%p\n",&s1[0])
fmt.Printf("对应数组元素的地址%p\n",&months[4])
}

对切片读写

package main

import (
"fmt"
) func main() {
//创建数组data
data := [...]int{0, 1, 2, 3, 4, 5}
//切片s [2,3]
s := data[2:4]
//切片读写操作目标是底层数组data
s[0] += 100
s[1] += 200
fmt.Println(s)
fmt.Println(data)
}

运行结果

[102 203]
[0 1 102 203 4 5]

2.1. 创建切片的方式

  1. 定义切片,然后引用已经创建好的数组,数组可见
  2. 内置make函数创建切片,底层数组看不见,只能通过slice访问元素

make创建切片内存分配图

package main

import (
"fmt"
)
/*
内置make函数,参数(类型,len,cap),注意cap大于len,容量可以省略,默认等于长度
切片有默认值
*/
var slice0 []int = make([]int, 10)
var slice1 = make([]int, 10)
var slice2 = make([]int, 10, 10) func main() {
fmt.Printf("make全局slice0 :%v\n", slice0)
fmt.Printf("make全局slice1 :%v\n", slice1)
fmt.Printf("make全局slice2 :%v\n", slice2)
fmt.Println("--------------------------------------")
slice3 := make([]int, 10)
slice4 := make([]int, 10)
slice5 := make([]int, 10, 10)
slice5[0] = 11
slice5[1] = 22
fmt.Printf("make局部slice3 :%v\n", slice3)
fmt.Printf("make局部slice4 :%v\n", slice4)
fmt.Printf("make局部slice5 :%v\n", slice5)
}
  1. 定义切片直接对应数组,如同make方式
package main

import "fmt"

func main() {
//第三种方式,原理类似make,数组看不见,由make维护
var s1 []int = []int{1, 2, 3, 4, 5}
fmt.Println(s1)
fmt.Println(len(s1))
fmt.Println(cap(s1))
}

4.遍历切片

package main

import "fmt"

func main() {
var arr [5]int = [...]int{11, 22, 33, 44, 55}
s1 := arr[1:4]
//for循环遍历
for i := 0; i < len(s1); i++ {
fmt.Printf("s1[%v]=%v\n", i, s1[i])
}
fmt.Println() //for range方式遍历切片
for i, v := range s1 {
fmt.Printf("索引i=%v 值v=%v\n", i, v)
}
}

5.切片案例

package main

import "fmt"

func main() {
var array1 = [...]int{11, 22, 33, 44}
slice1 := array1[1:4] //11,22,33
slice2 := array1[1:] //22,33,44
slice3 := array1[:] //11,22,33,44
slice4 := slice3[:2] //slice4=[11,22] 切片再切片
fmt.Println(slice1)
fmt.Println(slice2)
fmt.Println(slice3)
fmt.Println(slice4)
}

6.cap是内置函数,统计切片容量,最大存放多少元素

7.切片扩容,append内置函数,向尾部添加数据,返回新的slice对象

package main

import "fmt"

func main() {
//创建切片
var slice1 []int = []int{100, 200, 300}
fmt.Printf("slice1容量=%v 长度=%v\n", cap(slice1), len(slice1))
//给切片追加新元素
//容量扩容机制是2倍扩容
slice1 = append(slice1, 400)
fmt.Printf("slice1扩容后容量=%v 长度=%v\n", cap(slice1), len(slice1))
fmt.Println(slice1) //切片扩容切片,slice1... 语法糖代表展开切片元素
slice1=append(slice1,slice1...)
fmt.Println(slice1)
}
/*
append原理就是对底层数组扩容,go会创建新的数组,将原本元素拷贝到新的数组中
slice重新引用新的数组
这个数组不可见
*/

8.切片拷贝

package main

import "fmt"

func main() {
//创建切片
var slice1 []int = []int{11, 22, 33, 44}
//make创建切片,长度是10
var slice2 = make([]int, 10)
copy(slice2, slice1) //把slice1的值拷贝给slice2
fmt.Println(slice1) //[11 22 33 44]
fmt.Println(slice2) //[11 22 33 44 0 0 0 0 0 0]
//slice1和slice2数据独立,互不影响
slice1[0] = 123
fmt.Println(slice1)
fmt.Println(slice2)
}

9.全切片表达式

array[x:y:z]

x切片内容 [x:y]

Y切片长度: y-x

Z切片容量:z-x

package main

import (
"fmt"
) //官网资料
// https://golang.google.cn/ref/spec#Slice_expressions
func main() {
//10:2代表索引10的元素是2
data := [...]int{0, 1, 2, 3, 4, 10: 2}
fmt.Println(data)
s := data[1:2:3] //data[start:end:数字-start] 这个s容量是3-1=2
fmt.Printf("扩容前s的容量是:%v\n", cap(s))
s = append(s, 100, 200) // 一次 append 两个值,超出 s.cap 限制。
fmt.Println(s, data) // 重新分配底层数组,与原数组无关。
fmt.Printf("扩容后s的容量=%v\n", cap(s)) //二倍扩容
fmt.Println(&s[0], &data[0]) // 比对底层数组起始指针。
}

3. string和slice的联系

1)string底层就是byte数组,因此string同样可以进行切片处理

package main

import "fmt"

func main() {
str1 := "yugo niubi"
//对str1进行切片
s1 := str1[:4]
fmt.Println(s1)//yugo
}

2)string修改的两种方式

package main

import (
"fmt"
) func main() {
str1 := "yugo niubi"
//string是不可变的,也无法通过切片修改值
//str1[0] = 's' 编译器失败 //修改string的方法,需要string转化为[]byte,修改后转为string
arr1 := []byte(str1) //类型强转
arr1[0] = 'g'
str1 = string(arr1)
fmt.Printf("str1=%v\n", str1) //[]byte只能处理英文和数字,不能处理汉字,汉字3个字节,会出现乱码
//将string转为[]rune,按字符处理,兼容汉字
arr2 := []rune(str1)
arr2[0] = '于'
str1 = string(arr2)
fmt.Printf("str1=%v\n", str1)
}

3.9 Go Slice切片的更多相关文章

  1. golang:slice切片

    一直对slice切片这个概念理解的不是太透彻,之前学习python的就没搞清楚,不过平时就用python写个工具啥的,也没把这个当回事去花时间解决. 最近使用go开发又遇到这个问题,于是打算彻底把这个 ...

  2. golang slice切片的原理以及内置函数cap, len

    golang中slice(切片)是常用的类型, slice是对数组进行封装 package main import ( "fmt" "strconv") fun ...

  3. python定制类(1):__getitem__和slice切片

    python定制类(1):__getitem__和slice切片 1.__getitem__的简单用法: 当一个类中定义了__getitem__方法,那么它的实例对象便拥有了通过下标来索引的能力. c ...

  4. golang基础---Slice切片

    切片Slice在go语言中是单独的类型(指向底层的数组),不同于python(对可迭代对象操作的工具),注意区分数组和slice的区别 定义一个空slice,格式var s []int,这种既没有长度 ...

  5. Go语言核心之美 3.2-slice切片

    Slice(切片)是长度可变的元素序列(与之相应,上一节中的数组是不可变的),每一个元素都有同样的类型.slice类型写作[]T.T是元素类型.slice和数组写法非常像,差别在于slice没有指定长 ...

  6. Go - Slice 切片

    概述 切片是一种动态数组,比数组操作灵活,长度不是固定的,可以进行追加和删除. len() 和 cap() 返回结果可相同和不同. 声明切片 //demo_7.go package main impo ...

  7. Go(03) slice切片的使用

    原文链接 http://www.limerence2017.com/2019/05/08/golang05/#more golang 的引用类型和内置类型变量 golang 中变量类型分为引用类型和值 ...

  8. [日常] Go语言圣经-Slice切片习题

    1.Slice(切片)代表变长的序列,序列中每个元素都有相同的类型,一个slice类型一般写作[]T,其中T代表slice中元素的类型:slice的语法和数组很像,只是没有固定长度而已,slice的底 ...

  9. golang 数组以及slice切片

    老虞学GoLang笔记-数组和切片   数组 Arrays 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值.在初始化后长度是固定的,无法修改其 ...

随机推荐

  1. python学习06循环

    '''while''''''while 布尔表达式:冒号不能省略''''''1+2+3+...+10'''i=1sum1=0while i<=10: sum1+=i i+=1print(sum1 ...

  2. 非阻塞同步机制和CAS

    目录 什么是非阻塞同步 悲观锁和乐观锁 CAS 非阻塞同步机制和CAS 我们知道在java 5之前同步是通过Synchronized关键字来实现的,在java 5之后,java.util.concur ...

  3. centos7源码安装Apache及Tomcat

    源码安装Apache (1) 一.通过 https://apr.apache.org/  下载 APR 和 APR-util 通过 http://httpd.apache.org/download.c ...

  4. 第八章服务器raid及配置实战

      版本 特点 磁盘个数 可用空间 故障磁盘数 应用环境 RAID0 读写速度快,数据容易丢失 两个 全部 一块 测试,临时性 RAID1 读写速度慢,数据可靠 至少两个,可以2的倍数 总容量的一半 ...

  5. 工程师泄露5G核心技术文档 被判有期徒刑三年缓刑四年

    2002 年至 2017 年 1 月,黄某瑜就职于中兴通讯公司,担任过射频工程师.无线架构师等职务.2008 年 4 月至 2016 年 10 月,王某就职于中兴通讯公司西安研究所,担任过 RRU 部 ...

  6. 定了,这个vue.js开源项目,面试时,一定会考问

     因为现在的网店,都是用的商城系统, 而实体店都是入座后,扫码打开网上商城进行选购(餐饮,超市等),所以,vue.js迅速开发网上购物商城系统成为了香饽饽, 本人开源2020年4月开发的购物商城系统, ...

  7. Vue Cli 3 报错:router is not defined

    报错内容: 报错原因: 代码全部放在了路由配置的main.js文件里,router没有定义,使用的时候报undefined 解决方法: 把router.beforeEach放在main.js里面

  8. "net.sf.hibernate.PropertyValueException"

    2019独角兽企业重金招聘Python工程师标准>>> 如果你遇到了下面的错误信息,例如: ERROR [Importing data task] [confluence.impor ...

  9. 通过express框架为前端提供api(数据),妈妈再也不用担心后端不给我数据了~

    个人网站 https://iiter.cn 程序员导航站 开业啦,欢迎各位观众姥爷赏脸参观,如有意见或建议希望能够不吝赐教! 首先,确保自己安装了express框架. 没有安装的同学可以参照下面这篇博 ...

  10. MySQL必知必会1-20章读书笔记

    MySQL备忘 目录 目录 使用MySQL 检索数据 排序检索数据 过滤数据 数据过滤 用通配符进行过滤 用正则表达式进行搜索 创建计算字段 使用数据处理函数 数值处理函数 汇总数据 分组数据 使用子 ...