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. 2019-2020-1 20199329《Linux内核原理与分析》第四周作业

    <Linux内核原理与分析>第四周作业 一.上周问题总结: 虚拟机环境缺少部分库文件 书本知识使用不够熟练 二.本周学习内容: 1.实验楼环境使用gdb跟踪调试内核 1.1 在该环境下输入 ...

  2. How to permit SSH root Login in Ubuntu 18.04

    https://www.ubuntu18.com/ssh-permitrootlogin/ SSH root login is disabled by default in Ubuntu 18.04. ...

  3. Python带你做个愉快的"动森"玩家! (超简单代码)

    最近Switch上的<动物森友会>可谓是炙手可热,它几乎算是任天堂版的<模拟人生>了,它的最新游戏<集合啦!动物森友会>(以下称“动森”)在发售后,取得了不错的媒体 ...

  4. 理解分布式一致性:Paxos协议之Multi-Paxos

    理解分布式一致性:Paxos协议之Multi-Paxos Multi-Paxos without failures Multi-Paxos when phase 1 can be skipped Mu ...

  5. Firefox 66 发布,阻止网站自动播放声音

    Firefox 66 发布了,此版本在桌面版中带来的新特性包括: Firefox 现在阻止网站自动播放声音,如果需要可以单独调整 改进的搜索体验: 当打开许多选项卡时,可以更快地查找特定网页:现在可以 ...

  6. SSH 超时设置

    在阿里云买了一台乞丐版服务器,搭了一个博客,安装了java,mysql,redis等服务,把以前写的知乎爬虫部署上去,看看爬取效果.程序运行一段时间后,发现cmder上的日志不打了,我原以为爬虫挂了, ...

  7. jQuery里面click、this事件遇到(Django模型里for)相同的id名和class名想获取值

    遇到的原型是这样的!下面我把它简化一下; click事件: 在浏览器里面只能获取横线上面的值,和下面的第一个值!! 这是因为id等级比class高,而且js要求id不能重复! 当 转载于:https: ...

  8. 2019 Multi-University Training Contest 10 I Block Breaker

    Problem Description Given a rectangle frame of size n×m. Initially, the frame is strewn with n×m squ ...

  9. 2020.2.27——STL初步

    注:本文主要针对STL中的常用的操作进行总结 目录: 1.swap 2.sort 3.reverse 4.min,max(比较简单,暂且略过) 5._gcd 6.lower_bound &&a ...

  10. 【Java新特性】Lambda表达式典型案例,你想要的的都在这儿了!!

    写在前面 不得不说,有些小伙伴的学习热情真高,学完了Lambda表达式的语法,想来几个典型案例再强化下.于是问冰河能否给几个Lambda表达式的典型使用示例.于是乎,便有了这篇文章. 案例一 需求 调 ...