go语言---slice

https://blog.csdn.net/cyk2396/article/details/78893420

一.数组切片的使用:

//1.基于数组创建数组切片
var array [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var sliceMy = array[1:7] //array[startIndex:endIndex] 不包含endIndex
//2.直接创建数组切片
slice2 := make([]int, 5, 10)
//3.直接创建并初始化数组切片
slice3 := []int{1, 2, 3, 4, 5, 6}
//4.基于数组切片创建数组切片
slice5 := slice3[:4]
//5.遍历数组切片
for i, v := range slice3 {
fmt.Println(i, v)
}
//6.len()和cap()
var len = len(slice2) //数组切片的长度
var cap = cap(sliceMy) //数组切片的容量
fmt.Println("len(slice2) =", len)
fmt.Println("cap(slice) =", cap)
//7.append() 会生成新的数组切片
slice4 := append(slice2, 6, 7, 8)
slice4 = append(slice4, slice3...)
fmt.Println(slice4)
fmt.Println(slice5)
//8.copy() 如果进行操作的两个数组切片元素个数不一致,将会按照个数较小的数组切片进行复制
copy(slice2, slice3) //将slice3的前五个元素复制给slice2
fmt.Println(slice2, slice3)

二.数组切片数据结构分析:

数组切片slice的数据结构如下,一个指向真实array地址的指针ptr,slice的长度len和容量cap

// slice 数据结构
type slice struct {
array unsafe.Pointer
len int
cap int
}

当传参时,函数接收到的参数是数组切片的一个复制,虽然两个是不同的变量,但是它们都有一个指向同一个地址空间的array指针,当修改一个数组切片时,另外一个也会改变,所以数组切片看起来是引用传递,其实是值传递。

三.append()方法解析:

3.1 数组切片不扩容的情况

运行以下代码思考一个问题:s1和s2是指向同一个底层数组吗?

func main() {
array := [20]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := array[:5]
s2 := append(s1, 10)
fmt.Println("s1 =", s1)
fmt.Println("s2 =", s2)
s2[0] = 0
fmt.Println("s1 =", s1)
fmt.Println("s2 =", s2)
}

输出结果:

s1 = [1 2 3 4 5]

s2 = [1 2 3 4 5 10]

s1 = [0 2 3 4 5]

s2 = [0 2 3 4 5 10]

由第一行和第二行结果看来,似乎这是指向两个不同的数组;但是当修改了s2,发现s1也跟着改变了,这又表明二者是指向同一个数组。到底真相是怎样的呢?

运行以下代码:

import (
"fmt"
"unsafe"
) type Slice struct {
ptr unsafe.Pointer // Array pointer
len int // slice length
cap int // slice capacity
} func main() {
array := [20]int{1, 2, 3, 4, 5, 6, 7, 8, 9}
s1 := array[:5]
s2 := append(s1, 10)
s2[0] = 0
// 把slice转换成自定义的 Slice struct
slice1 := (*Slice)(unsafe.Pointer(&s1))
fmt.Printf("ptr:%v len:%v cap:%v \n", slice1.ptr, slice1.len, slice1.cap)
slice2 := (*Slice)(unsafe.Pointer(&s2))
fmt.Printf("ptr:%v len:%v cap:%v \n", slice2.ptr, slice2.len, slice2.cap)
}

输出结果:

ptr:0xc04205e0a0 len:5 cap:20

ptr:0xc04205e0a0 len:6 cap:20

由结果可知:ptr指针存储的是数组中的首地址的值,并且这两个值相同,所以s1和s2确实是指向同一个底层数组。但是,这两个数组切片的元素不同,这个可以根据首地址和数组切片长度len来确定不同的数组切片应该包含哪些元素,因为s1和s2虽然指向同一个底层数组,但是二者的len不同。通过这个demo,也验证了数组切片传参方式也是值传递。

3.2 数组切片扩容的情况:

运行以下代码,思考与不扩容情况的不同之处,以及为什么

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

输出结果:

s1 = [1 2 3 4 5 6 7 8 9]

s2 = [1 2 3 4 5 6 7 8 9 10]

s1 = [1 2 3 4 5 6 7 8 9]

s2 = [0 2 3 4 5 6 7 8 9 10]

根据结果我们发现,修改s2后,s1并未改变,这说明当append()后,s1和s2并未指向同一个底层数组,这又是为什么呢?

同样,我们接着运行以下代码:

import (
"fmt"
"unsafe"
) type Slice struct {
ptr unsafe.Pointer // Array pointer
len int // slice length
cap int // slice capacity
} func main() {
s1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
s2 := append(s1, 10)
fmt.Println("s1 =", s1)
fmt.Println("s2 =", s2)
s2[0] = 0
fmt.Println("s1 =", s1)
fmt.Println("s2 =", s2)
// 把slice转换成自定义的 Slice struct
slice1 := (*Slice)(unsafe.Pointer(&s1))
fmt.Printf("ptr:%v len:%v cap:%v \n", slice1.ptr, slice1.len, slice1.cap)
slice2 := (*Slice)(unsafe.Pointer(&s2))
fmt.Printf("ptr:%v len:%v cap:%v \n", slice2.ptr, slice2.len, slice2.cap)
}

输出结果:

s1 = [1 2 3 4 5 6 7 8 9]

s2 = [1 2 3 4 5 6 7 8 9 10]

s1 = [1 2 3 4 5 6 7 8 9]

s2 = [0 2 3 4 5 6 7 8 9 10]

ptr:0xc04207a000 len:9 cap:9

ptr:0xc04207c000 len:10 cap:18

由结果可知:append()后,s1和s2确实指向了不同的底层数组,并且二者的数组容量cap也不相同了。过程是这样的:当append()时,发现数组容量不够用,于是开辟了新的数组空间,cap变为原来的两倍,s2指向了这个新的数组,所以当修改s2时,s1不受影响

go语言---slice的更多相关文章

  1. Go语言Slice作为函数参数详解

    Go语言Slice作为函数参数详解 前言 首先要明确Go语言中实质只有值传递,引用传递和指针传递是相对于参数类型来说. 个人认为上诉的结论不对,把引用类型看做对指针的封装,一般封装为结构体,结构体是值 ...

  2. GO语言slice详解(结合源码)

    一.GO语言中slice的定义 slice 是一种结构体类型,在源码中的定义为: src/runtime/slice.go type slice struct { array unsafe.Point ...

  3. go语言slice的理解

    Golang slice yongsean  作者 2017.02.17 00:07  打开App 创建切片,len.cap.append b := make([]int, 5) println(le ...

  4. Go语言Slice操作.

    1.基本使用方法: a = append(a, b...) 比如:list = appened(list,[]int{1,2,3,4}...) 能够用来合并两个列表. 不用这样了 :list := m ...

  5. Zeroc Ice原理介绍

    Ice介绍         Ice(Internet Communications Engine)是ZeroC公司的杰作,继承了CORBA的血统,是新一代的面向对象的分布式系统中间件.Ice是RPC通 ...

  6. 《ZeroC Ice 权威指南》笔记

    Ice介绍         Ice(Internet Communications Engine)是ZeroC公司的杰作,继承了CORBA的血统,是新一代的面向对象的分布式系统中间件.Ice是RPC通 ...

  7. Ice框架介绍

    概述 Ice是一个开源的综合性RPC框架,以高性能和原生支持微服务的架构而著称.提供了很多可以直接使用的组件,如注册中心IceGrid,部署工具IcePatch2,防火墙穿透Glacier2,发布订阅 ...

  8. go语言的 数组、slice、map使用(转)

    golang群 点击加入 go语言的 数组.slice.map使用, 由于网上有很好的说明, 不需要再写了,请看这几篇: Go语言中的 Array, Slice和 Map 深入学习golang五篇,以 ...

  9. ICE学习第三步-----Slice语言

    ICE:Slice语言(一)-编译 Introduce简介 Slice(Specification language for ice)是分离对象和对象的实现的基础的抽象机制.Slice在客户端和服务器 ...

随机推荐

  1. python爬取百度文库所有内容

    转载自 GitHub 的 Jack-Cherish 大神 基本环境配置 版本:python3 系统:Windows 相关模块: import requests import re import jso ...

  2. 第十八节:Scrapy爬虫框架之settings文件详解

    # -*- coding: utf-8 -*- # Scrapy settings for maoyan project## For simplicity, this file contains on ...

  3. LeetCode(88)Merge Sorted Array

    题目 Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note ...

  4. 对于BFC(block format context)理解

    目录 前言 Box: CSS布局的基本单位&盒模型 什么是BFC?(Block formatting contexts) 元素与盒 正常流 块级与行内级 产生垂直外边距合并的必备条件 前言 什 ...

  5. MTK android L使用汇顶TP如何使用B协议

    使用B协议上报之前的代码: #include "tpd.h" #include "tpd_custom_gt9xx.h" #ifndef TPD_NO_GPIO ...

  6. 【ZJOI2017 Round1练习&BZOJ5350】D5T1 masodik(DP,斜率优化)

    题意:你要从(0,0)点走到(n,m), 每次只能往 x 轴或者 y 轴正方向移动一个单位距离.从(i,j)移动到(i,j+1)的代价为 ri,从(i,j)移动到(i+1,j)的代价为 cj. 求最小 ...

  7. msp430入门编程0

    msp430单片机最小系统 msp430入门学习 msp430入门编程

  8. Android定位(是否使用GPS进行定位)

    TencentLocationRequest request = TencentLocationRequest.create(); request.setRequestLevel(TencentLoc ...

  9. 自定义View实现跟随手指的小球

    package com.pingyijinren.test; import android.content.Context; import android.graphics.Canvas; impor ...

  10. Ubuntu系统备份工具大全(官方整理推荐)

    其实官方在系统备份这块已经有Wiki整理和收集各类实用的工具.以下是翻译自官方Wiki的部分文档: 备份工具  wiki文档实用程序 工具 界面 格式类型 Raw/File 支持 远程 增量 差异 自 ...