首页 > 其他分享 >GO 语言中 slice 的理解

GO 语言中 slice 的理解

时间:2023-06-25 10:26:39浏览次数:47  
标签:origin slice 语言 after func GO append 底层

GO 语言中 slice 理解

为什么说 Go 语言的 slice 是引用类型,其底层实现明明是一个结构体?

slice 的底层实现是一个包含三个字段的结构体:指向底层数组的指针、slice 的长度和 slice 的容量。当我们对 slice 进行操作时,例如添加或删除元素,实际上是在底层数组中进行操作。由于 slice 是一个指向底层数组的指针,因此多个 slice 可以共享同一个底层数组,这也是 slice 被称为引用类型的原因,也因此可以将其赋值为 nil(实际上是将底层结构体中的指向底层数组的指针设置为 nil)。

需要注意的是,虽然 slice 是引用类型,但是它并不是一个指针类型。因此,我们可以对 slice 进行赋值和传递,而不需要使用指针。这也是 Go 语言中 slice 的一个优点,它可以方便地进行传递和复制,而不需要担心底层数组的复制和传递带来的性能问题。

除了 slice,Go 语言中还有其他的引用类型,例如 map 和 channel

函数调用中修改 slice 的元素会影响原 slice 吗?

这里要分具体情况,如果在函数中对 slice 进行了 append 操作导致了 slice 扩容,那么扩容之后的 slice 的底层数据与原 slice 分离,就不会相互影响,否则会影响原 slice

//  初始化一个长度和容量不相同的 slice,函数中 append 操作没有导致底层数据扩容
// 所以对 slice[0] 的修改会影响原 slice
func Test_isSliceChangeIfAppend(t *testing.T) {
    slice := make([]int, 5, 10)
    fmt.Printf("origin slice:%v\n", slice)
    isSliceChangeIfAppend(slice)
    fmt.Printf("after append out func:%v\n", slice)
}

func isSliceChangeIfAppend(origin []int) {
    origin = append(origin, 1, 2, 3)
    origin[0] = 1
    fmt.Printf("after append in func:%v\n", origin)
}

-----output-----
origin slice:[0 0 0 0 0]
after append in func:[1 0 0 0 0 1 2 3]
after append out func:[1 0 0 0 0]
//  同上面的代码,初始化一个长度和容量相同的 slice
// 函数中的 append 操作就一定会扩容,后续修改也就不会影响原 slice
func Test_isSliceChangeIfAppend(t *testing.T) {
    // 初始化一个长度和容量相同的 slice
    slice := make([]int, 5)
    fmt.Printf("origin slice:%v\n", slice)
    isSliceChangeIfAppend(slice)
    fmt.Printf("after append out func:%v\n", slice)
}

func isSliceChangeIfAppend(origin []int) {
    origin = append(origin, 1, 2, 3)
    origin[0] = 1
    fmt.Printf("after append in func:%v\n", origin)
}

-----output-----
origin slice:[0 0 0 0 0]
after append in func:[1 0 0 0 0 1 2 3]
after append out func:[0 0 0 0 0]

![图片](https://mmbiz.qpic.cn/mmbiz_png/2fBauyxIV9YmLFQeheVRlib675c1S34fYGl7Y1RGmdwISIncPcibic1phDVRPaqUZKJUCx0lINWdqtWcJOpArFsKA/640?wx_fmt=png)

标签:origin,slice,语言,after,func,GO,append,底层
From: https://www.cnblogs.com/orchidzjl/p/17502236.html

相关文章

  • MongoDB常用命令指南
    定义......
  • golang入门,基础语法demo(1)
    packagemainimport"fmt"funcmain(){//声明变量varaint//使用var关键字声明变量a,类型为inta=1//赋值fmt.Println(a)//类型推导//使用:=自动推导类型并声明变量b,其类型为stringb:="helloworld"fmt.Pr......
  • C语言中将二维数组作为函数参数来传递
    C语言中经常需要通过函数传递二维数组,有三种方法可以实现,如下:方法一,形参给出第二维的长度#include<stdio.h>voidfunc(intn,charstr[][5]){inti;for(i=0;i<n;i++)printf("/nstr[%d]=%s/n",i,str[i]);}voidmain(){char*p[3];charstr[]......
  • Mongo与MySql区别
    1.MongoDBmongoDB是一种分布式文档型数据库,具有分布式架构设计。mongoDB分布式架构包含:分片、副本和分布式查询路由1.1分片MongoDB分片技术将数据分割成多个分片(shard),每个分片存储部分数据。分片可以按照数据的范围、has值、分片键等方式进行分配。在分片集群中有一个特定的m......
  • Dart 开发语言概览
    本文地址目录目录目录Dart开发语言概览重要概念变量latefinal和const注释内置类型数字intdouble字符串String布尔bool数组List无序集合Set键值对Map函数Dart开发语言概览原文GitHubDartPad版本演变关键字重要概念以下均假设开启了空安全所有变量引用......
  • C语言-assert.h
    assert() assert.h头文件定义了宏assert(),用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行。这个宏常常被称为“断言”。assert(PI>3);上面代码在程序运行到这一行语句时,验证变量PI是否大于3。如果确实大于3,程序继续运行,否则就会终止运行,并且给出报错信息提示。asser......
  • GoLang图形用户界面编程实战(GUI编程)—fyne框架(三)
    fyne中文乱码的两种解决方法方法一(使用embed):embed是Go1.16新特性,以后会有专门的介绍。1、拷贝字体到项目目录项目根目录下新建resource目录,把字体文件拷贝到其中。2、在resource目录下新建resource_export.go文件。resource_export.go代码:packageresourceimport_"emb......
  • 容器基础-- namespace,Cgoup 和 UnionFS
    Namespace什么是Namespace?这里的"namespace"指的是Linuxnamespace技术,它是Linux内核实现的一种隔离方案。简而言之,Linux操作系统能够为不同的进程分配不同的namespace,每个namespace都具有独立的资源分配,从而实现了进程间的隔离。如果你的Linux安装了GCC,可以通过......
  • 一篇玩转Gorm框架的CRUD
    简介关于ORM(Object-RelationalMapping)ORM其实指的是将关系型数据库中的数据和面向对象程序中对象模型进行映射的技术;ORM可以用来自动化处理SQL语句的生成和执行,程序员可以更专注于业务逻辑的实现而不是数据的细节。为什么需要ORM?(参考gpt,结合自身使用过程)提高开发效率(自动化......
  • C语言里面那些你必须知道的常用关键字(详细讲解)
    前言  哈喽,各位铁汁们好啊!✨今天来给大家带来的是C语言中我们常用的关键字静态static的详细讲解和typedef、#define定义常量和宏。  既然是详解想必大家必定是想学一些平常学不到的东西吧!这里博主给大家详细讲解static修饰的变量在内存重视如何存储的,顺带给大家讲一下C/C++......