详解go语言的array和slice 【二】

  上一篇  详解go语言的array和slice 【一】已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多。上一篇的最后讲解到创建新的slice时使用第三个索引来限制slice的容量,在操作新slice时,如果新slice的容量大于长度时,添加新元素依然后使源的相应元素改变。这一篇里我会讲解到如何避免这些问题,以及迭代、和做为方法参数方面的知识点。

slice的长度和容量设置为同一个值

  如果在创建新的slice时我们把他的长度和容量的值设置为样的值,那么在append新元素时,底层会创建一个新的array并把之前的值复制过去。这样就不会影响之前共同的底层array了。

    // 创建一个容量和长度均为6的slice
    slice1 := []int{5, 23, 10, 2, 61, 33}
    // 对slices1进行切片,长度为2容量为3
    slice2 := slice1[1:3:3]
    fmt.Println("cap", cap(slice2))
    fmt.Println("slice2", slice2)

    //修改一个共同指向的元素
    //两个slice的值都会修改
    slice2[0] = 11111
    fmt.Println("slice1", slice1)
    fmt.Println("slice2", slice2)

    // 增加一个元素
    slice2 = append(slice2, 55555)

    fmt.Println("slice1: ", slice1)
    fmt.Println("slice2: ", slice2)

  输出结果

cap 2
slice2 [23 10]
slice1 [5 11111 10 2 61 33]
slice2 [11111 10]
slice1:  [5 11111 10 2 61 33]
slice2:  [11111 10 55555]

  代码中的长度和容量是一样的,长度和容量的计算公式看我的上一篇博客。增加一个元素后,原来共同指向的底层数据是没有变的。因为slice2的底层array被重新赋值了。

迭代slice

  go语言内置一个关键字range用于迭代集合,当然他也可以迭代slice,也可以使用  _  来忽略我们不关心的元素,但是如果只关心index则不需这么写 for index,_ := range slice1。下在给出完整代码

    // 创建一个容量和长度均为6的slice
    slice1 := []int{5, 23, 10, 2, 61, 33}

    for index, value := range slice1 {
        fmt.Println("index: ", index, " value: ", value)
    }

    // 可以忽略我们不关心的元素
    // 只关心value
    for _, value := range slice1 {
        fmt.Println("value ", value)
    }

    // 只关心index, 可以不用 _
    for index := range slice1 {
        fmt.Println("index: ", index)
    }

  需要注意的是rang 迭代的value值并是一个复本,我们可以对比一下迭代的value和原slice内相应index下value的地址:

    // 创建一个容量和长度均为6的slice
    slice1 := []int{5, 23, 10, 2, 61, 33}

    for index, value := range slice1 {
        fmt.Println("index: ", index, " value address : ", &value, " slice1 value address", &slice1[index])

    }

  输出结果

index:  0  value address :  0xc04204e088  slice1 value address 0xc04206a030
index:  1  value address :  0xc04204e088  slice1 value address 0xc04206a038
index:  2  value address :  0xc04204e088  slice1 value address 0xc04206a040
index:  3  value address :  0xc04204e088  slice1 value address 0xc04206a048
index:  4  value address :  0xc04204e088  slice1 value address 0xc04206a050
index:  5  value address :  0xc04204e088  slice1 value address 0xc04206a058

  slice1中value的地址是不断变化的。而迭代的value值的地址没有变化,这是因为value是一个变量,为次迭代的时候赋不同的值。我们把代码写成下面这样,你就清楚了

    var index, value int
    for index, value = range slice1 {
        fmt.Println("index: ", index, &index, " value address : ", &value, " slice1 value address", &slice1[index])

    }

  除了使用rang 也可以使用传统的for循环来做迭代

    slice1 := []int{5, 23, 10, 2, 61, 33}

    for i, len := 1, len(slice1); i < len; i++ {
        fmt.Println("index: ", i, " value:", slice1[i])
    }

slice作为方法参数

  由于slice的特殊结构,有一个指针指向一个数组

    s := make([]int, 2, 5)
    fmt.Println("len: ", len(s))
    fmt.Println("cap: ", cap(s))
    s = append(s, 2)

    s[0] = 12

  所以,slice做为方法的参数传递时,只会复制slice本身而不会复制slice底层的array.如果我们创建一个int类型有100万长度的slice ,把他传递给一个方法时,只需要复制24个字节就够了。指针需要8个,长度和容量都是8个。

const size int = 1000 * 1000

func main() {
    slice0 := make([]int, size)
    fmt.Println("slice0 len: ", len(slice0), " cap :", cap(slice0))
    doSomeThing(slice0)
}

func doSomeThing(s []int) {
    fmt.Println(len(s))
}

时间: 2024-12-26 08:25:21

详解go语言的array和slice 【二】的相关文章

详解User Defined Java Class步骤(二)

 详解User Defined Java Class步骤(二) kettle中的"user defined java class"步骤,也称UDJC步骤,从4.0版本就有,功能非常强大,无所不能:可以在其中写任意代码,却不影响效率.本文将详细介绍在不同场景中用示例展示如果使用该步骤,由于内容非常多,便于阅读方便,把内容分成三部分,请完整看完全部内容,示例代码在这里下载. 如果没有从第一部分开始,请访问第一部分. 使用步骤参数(Step Parameter) 如果你写了一段代码,如果

【java项目实战】Servlet详解以及Servlet编写登陆页面(二)

Servlet是Sun公司提供的一门用于开发动态web网页的技术.Sun公司在API中提供了一个servlet接口,我们如果想使用java程序开发一个动态的web网页,只需要实现servelet接口,并把类部署到web服务器上就可以运行了. 到底什么是Servlet呢? 通俗一点,只要是实现了servlet接口的java程序,均称Servlet.Servlet是由sun公司命名的,Servlet = Server + Applet(Applet表示小应用程序),Servlet是在服务器端运行的小

详解Javascript中的Array对象

基础介绍 创建数组 和Object对象一样,创建Array也有2种方式:构造函数.字面量法. 构造函数创建 使用构造函数的方式可以通过new关键字来声明,如下所示: 12 var arr = new Array();console.log(arr);//[] 当然也可以不通过new关键字来声明: 12 var arr = Array();console.log(arr); //[] 如果知道数组元素的个数,也可以直接传入数字表示元素个数: 12 var arr2 = new Array(5);c

Linux进程上下文切换过程context_switch详解--Linux进程的管理与调度(二十一)【转】

转自:http://blog.csdn.net/gatieme/article/details/51872659 版权声明:本文为博主原创文章 && 转载请著名出处 @ http://blog.csdn.net/gatieme 目录(?)[-] 前景回顾 1 Linux的调度器组成 2 调度工作 进程上下文 1 进程上下文的概念 2 上下文切换 context_switch进程上下文切换 1 context_switch完全注释 2 prepare_arch_switch切换前的准备工作

LeetCode刷题 1. Two Sum 两数之和 详解 C++语言实现 java语言实现

Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. Example: Given nums = [2, 7, 11, 15]

详解 C 语言开发五子棋游戏以及游戏中的重要算法与思路

重拾 C 语言之后发现,原来 C 语言是那么的简洁,对于写小项目来讲,C 语言是那么的合适,然后,博主自己写了一个五子棋游戏,同样是基于博主自己封装的 nkCEngine 代码库编写,其实整个游戏里面大部分代码都用在逻辑处理上了,图形处理以及窗口创建的部分,因为有高度封装的 nkCEngine,基本上可以忽略不计,这篇博文来讲一讲 C 语言开发一个简单的五子棋游戏,这个游戏不包含人机对战的逻辑,所以唯一的难点估计就是在于如何判断下棋的一方在下棋时候是否获胜了,同时博主也会介绍一个游戏开发中最经常

详解C语言的main函数

如图所示:#include<stdio.h>这是一个头文件,包含的是C程序运行的C语言的库函数,只有包含了相关的头文件,在程序中才能调用.stdio表示输入输出控制.printf():就是来自这个头文件. int main(int argc ,const char *argv[]){...} :int 表示函数的返回值类型,main是函数名, ()里面的是参数,前面的关键字标示的是参数的类型 ,argc是命令行中的参数的个数,argv[]对应每一个参数. return是一个函数的返回值,当函数

malloc函数详解 C语言逻辑运算符

今天写线性表的实现,又遇到了很多的难题,C语言的指针真的没学扎实.很多基础都忘了. 一是 :malloc 函数的使用. 二是:C语言逻辑运算符. 一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc.h> (注意:alloc.h 与 malloc.h 的内容是完全一致的.) 功能:分配长度为num_bytes字节的内存块 说明:如果分配成功则返回指向被分

打开文件open()函数的使用方法详解--C语言函数

头文件:#include <sys/types.h>    #include <sys/stat.h>    #include <fcntl.h> 定义函数: int open(const char * pathname, int flags); int open(const char * pathname, int flags, mode_t mode); 函数说明: 参数 pathname 指向欲打开的文件路径字符串. 下列是参数flags 所能使用的旗标: O_R