Go基础编程 - 05 - 数组与切片

news2025/2/27 1:22:52

目录

    • 1. 数组
    • 2. 切片
      • 2.1. slice 声明、初始化
      • 2.2. slice 操作
      • 2.3. append() 追加切片、扩容
      • 2.4. 字符串和切片
    • 3. Copy
    • 4. Array、Slice 内存布局

上一篇:基本类型、常量和变量

下一篇:指针


1. 数组

数组是同一种类型固定长度的序列(有长度、类型构成)。一但定义,长度不可改变。

  • 数组为值类型,赋值和传参会复制整个数组,而不是指针。
  • 数组声明时,必须固定长度;长度是数组类型的一部分,不同长度的数组类型表示不同的类型([2]int[3]int 为不同的数组类型);
  • 数组未赋值,则初始化为类型缺省值(零值)。
  • 内置函数lencap都返回数组长度。
  • 越界访问产生panic。
  • 指针数组:[n]*T,数组指针:*[n]T
  • 值拷贝行为会造成性能问题,通常会建议使用 slice,或数组指针。
package main

import (
	"fmt"
	"reflect"
)

func main() {
    // 初始化
    var arr1 [5]int
    var arr2 = [5]int{0, 1, 2, 3, 4}
    var arr3 = [3]int{0, 2: 4}
    var arr4 = [...]int{1, 2, 3}
    fmt.Println(arr1, arr2, arr3, arr4)

    // 长度是数组类型的一部分,不同长度的数组类型为不同类型
    if reflect.TypeOf(arr1) == reflect.TypeOf(arr2) {
        fmt.Println("arr1 和 arr2 数据类型相同!")
    }
    if reflect.TypeOf(arr1) != reflect.TypeOf(arr3) {
        fmt.Println("arr1 和 arr3 数据类型不相同!")
    }

    // 数组为值类型:赋值和传参复制整个数组
    arr1copy := arr1
    arr1copy[0] = 10
    fmt.Println(arr1, arr1copy)

    // 值拷贝行为会造成性能问题,通常会建议使用 slice,或数组指针。
    fn := func(arr [5]int) {
        arr[1] = 20
    }
    fn(arr1)
    fmt.Println(arr1)

    // 指针数组:[n]*T
    var pa = [2]*int{new(int)}
    *pa[0] = 10
    pa[1] = new(int) // 引用类型必须先分配内存,须使用new分配内存
    *pa[1] = 20      // 若不分配内存(注释上一行代码),则产生panic: runtime error: invalid memory address or nil pointer dereference
    fmt.Printf("pa:%v  \n", pa)

    // 数组指针:*[n]T
    var ap *[3]int // var ap = new([3]int)
    ap = new([3]int)
    *ap = [3]int{4, 5, 6}
    fmt.Printf("ap:%v  psr:%p  type:%T  \n", *ap, ap, ap)

    // 多维数组
    multArr := [...][2]int{{0, 0}, {1, 1}, {2, 2}}
    fmt.Println(multArr)
}

2. 切片

切片并不是数组或数组指针。它通过内部指针和相关属性引用数组片段,以实现变长方案。

  • 切片是引用类型;底层数据结构是一个数组,可以看作是对数组某个连续片段的引用。
  • 切片是可变长的(包含长度、容量)。
  • 长度:用len()函数求长度,表示可用元素数量,读写操作不能超过该限制。
  • 容量:用cap()函数求最大容量,为切片底层数组的长度。
  • 扩容及规律: 扩容通常以 2 倍容量重新分配底层数组;当原有切片容量大于 1024 时,以 1.25 倍扩容。
  • 若 slice == nil,则 lencap结果都等于 0。

2.1. slice 声明、初始化

package main

import "fmt"

func main() {
    // 声明
    var s []int     
    if s == nil {
        fmt.Println("s is nil")
    }
    s1 := []int{1, 2, 3, 4}
    // 使用 make()
    var s2 []int = make([]int, 0)
    s3 := make([]int, 5)
    s4 := make([]int, 5, 8)

    fmt.Println(s, s1, s2, s3, s4)
    fmt.Println("Cap:", cap(s), cap(s1), cap(s2), cap(s3), cap(s4))

    // 从数组切片
    arr := [5]int{1, 2, 3, 4, 5}
    var s5 []int
    s5 = arr[1:4] // 前包后不包
    fmt.Println(s5, len(s5), cap(s5))
}

2.2. slice 操作

  • slice 的索引起点为 0。
  • 切片截取:s[i:j:max],满足 i <= j <= max;其中,i为起始索引(包含),省略值 0j结束索引(不包含),省略值len(s)max为截取最大索引,省略值len(s)
  • 截取新切片长度 = j - i
  • 截取新切片容量 = max - i
  • 截取新切片开始索引非 0,指针地址指向底层数组中新切片开始索引所在的地址;起始地址相同的slice指针地址相同,例:s[i], s[i:], s[i:j], s[i:j:max] 的指针引用地址都相同。
package main

import "fmt"

func main() {
    s := [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}

    v := s[0]
    fmt.Println(v)

    s1 := s[2:5]
    s2 := s[2:8]
    s3 := s[:10:12]

    fmt.Println("val", v, s1, s2, s3)
    fmt.Println("len", len(s1), len(s2), len(s3))
    fmt.Println("cap", cap(s1), cap(s2), cap(s3))
    fmt.Printf("prs %p %p %p \n", s1, s2, s3)
}

2.3. append() 追加切片、扩容

append() 向 slice 尾部添加数据,返回新的 slice 对象。

扩容通常以 2 倍容量重新分配底层数组。在大批量添加数据时,建议一次性分配足够大的空间,以减少内存分配和数据复制开销。或初始化足够长的 len 属性,改用索引号进行操作。及时释放不再使用的 slice 对象,避免持有过期数组,造成 GC 无法回收。

package main

import "fmt"

func main() {
    arr := []int{0, 1, 2, 3, 4}
    fmt.Println("len =", len(arr), "cap =", cap(arr))       // len = 5  cap = 5

    arr1 := append(arr, 5)       // 追加数据,超出原切片容量,则进行扩容
    fmt.Println("len =", len(arr1), "cap =", cap(arr1))     // len = 6  cap = 10
    fmt.Printf("prs: %p %p \n", arr, arr1)  // 对比底层数组起始指针,扩容后重新分配底层数组,与原数组无关。

    arr1 = append(arr1, []int{6, 7, 8, 9, 10}...)
    fmt.Println("len =", len(arr1), "cap =", cap(arr1))     // len = 11 cap = 20
}

2.4. 字符串和切片

string 底层就是一个 byte/rune 的数组,因此,也可以进行切片操作。

package main

import "fmt"

func main() {
    str := "Hello, Chain"

    s1 := str[:5]
    println(s1) // Hello

    //string 本身是不可变的,因此要改变string中字符;需将字符转为slice,进行更改,再转为string
    //str[0] = 'X'     // 报错:cannot assign to str[0] (value of type byte)

    s := []byte(str) // 英文字符使用 byte,代表ASCII码的一个字符
    // 赋值需要使用单引号(''),单引号定义一个字符,双引号定义个字符串
    s = append(s, '!')
    str = string(s)
    fmt.Println(str)

    str2 := "你好,中国"
    s2 := []rune(str2) // 包含中文字符使用 rune,代表一个UTF-8字符
    s2[3] = '伟'
    s2[4] = '大'
    s2 = append(s2, []rune{'的', '中', '国'}...)
    fmt.Println(string(s2))
}

3. Copy

  • 深拷贝:拷贝的是数据本身;值类型数据,默认是深拷贝,Array、Int、Sting、Struct、Bool、Float。
  • 浅拷贝:拷贝的是数据地址;引用类型数据,默认浅拷贝,Map、Slice。
package main

import "fmt"

func main() {
   arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
   arr2 := arr
   arr[1] = 10
   fmt.Println(arr, arr2)
   fmt.Printf("prs: %p %p \n", &arr, &arr2) // Array 属于深copy
   fmt.Println()

   s1 := arr[:6]
   s2 := arr[4:]
   s1[5] = 50 // Slice 属于浅copy
   fmt.Println(s1, s2)
   fmt.Printf("prs:%p %p \n", s1, s2)

   // copy函数只能用于切片,属于浅拷贝;允许元素区间重叠
   copy(s1, s2)
   s1[1] = 100
   fmt.Println(s1, s2, arr)
}

4. Array、Slice 内存布局


array-slice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1823663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新版eclipseSpringToolSuite4 get set方法自动生成注释(适用2019-03之后版本)

今天分享一个新版本eclipse 自动生成getter/setter文档注释的方法&#xff0c;看一下效果图 public class Test {//姓名private String name;/** * 获取 姓名 * return name 姓名 */public String getName() {return name;}/** * 设置 姓名 * param name 姓名 */public void …

frp55版本如何配置泛域名

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 前言 之前配置的好好的frp&#xff0c;结果到用的时候不能用了&#xff0c;直接影响了我早上的一堆rss订阅源不能用&#xff0c;群里的新闻简报也没有正常推送&#xff0c;今天又翻出来捋…

SpringCloud总结(springcloud alibaba)

目录 版本说明&#xff08;很重要&#xff09; springcloud alibaba对应组件版本说明 简述 spring cloud albaba 几大模块 周会讨论 - spring cloud alibaba每周都会有周会讨论,社区活跃 spring cloud alibaba官网 注册配置中心 简单介绍 nacos 步骤 示例代码 依赖…

C# WinForm —— 35 StatusStrip 介绍

1. 简介 状态栏 StatusStrip&#xff0c;默认在软件的最下方&#xff0c;用于显示系统时间、版本、进度条、账号、角色信息、操作位置信息等 可以在状态栏中添加的控件类型有&#xff1a;StatusLabel、ProgressBar、DropDownButton、SplitButton 2. 属性 属性解释(Name)控…

端午后的第一单cisa

需要的老板快来联系

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第41课-动态添加3D对象

【WEB前端2024】3D智体编程&#xff1a;乔布斯3D纪念馆-第41课-动态添加3D对象 使用dtns.network德塔世界&#xff08;开源的智体世界引擎&#xff09;&#xff0c;策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引擎…

实现流程自动化的警务反诈RPA:通过智能化技术提升警方反诈骗能力

电信诈骗一直以来都是公安机关重点打击的犯罪行为&#xff0c;随着信息技术的更新迭代&#xff0c;新型诈骗手段也层出不穷&#xff0c;传统的反诈手段已无法满足办案所需。在这一背景下&#xff0c;公安机关利用科技革命带来的契机&#xff0c;坚持以科技为反诈工作赋能&#…

鹧鸪云光伏业务管理系统,助力企业数智化发展

在当今数字化浪潮席卷全球的背景下&#xff0c;光伏行业作为绿色能源的重要组成部分&#xff0c;其业务管理的数智化转型显得尤为重要。鹧鸪云光伏业务管理系统&#xff0c;以其强大的功能和卓越的性能&#xff0c;正成为企业实现数智化转型的重要助力。 作为光伏行业的领军软…

LeetCode 119.杨辉三角 II

1.题目要求如图所示: 示例 1:输入: rowIndex 3 输出: [1,3,3,1]示例 2:输入: rowIndex 0 输出: [1]示例 3:输入: rowIndex 1 输出: [1,1]先用malloc函数创造一个二维数组&#xff0c;变成杨辉三角&#xff0c;然后再用一维数组找到所指的那一行: /*** Note: The returned…

循环订单激励:打造企业增长新引擎

循环订单激励&#xff1a;打造企业增长新引擎 在当今竞争激烈的商业环境中&#xff0c;许多企业都在寻求独特而高效的营销策略以吸引并留住客户。今天&#xff0c;我要为您介绍的是一种名为“循环订单激励”的新颖模式&#xff0c;它不仅能提升客户参与度&#xff0c;还能为企…

Python实现逻辑回归与判别分析--西瓜数据集

数据 数据data内容如下&#xff1a; 读取数据&#xff1a; import numpy as np import pandas as pd data pd.read_excel(D:/files/data.xlsx) 将汉字转化为01变量&#xff1a; label [] for i in data[好瓜]:l np.where(i 是,1,0)label.append(int(l)) data[label] lab…

南师大GIS专业2024排名NO.1!!!

南师大GIS 666 学科专业实力666&#xff0c;研究方向多多多&#xff01; 有学术方向有开发应用方向&#xff0c; 有GIS&#xff08;建模、数字地形、基础理论和三维GIS等&#xff09;、 有Cartography &#xff08;叙事地图、动态地图、地图风格迁移等&#…

线性规划问题——单纯形算法

第一步&#xff1a;化“约束标准型” 在每个等式约束中至少有一个变量的系数为正&#xff0c;且这个变量只在该约束中出现。在每个约束方程中选择一个这样的变量称为基本变量。 剩下变量称为非基本变量。 一个简单的栗子 上图是一个约束标准型线性规划的例子。 等式1&#x…

【总线】AMBA总线架构的发展历程

目录 引言 发展历程 第一代AMBA&#xff08;AMBA 1&#xff09; 第二代AMBA&#xff08;AMBA 2&#xff09; 第三代AMBA&#xff08;AMBA 3&#xff09; 第四代AMBA&#xff08;AMBA 4&#xff09; 第五代AMBA&#xff08;AMBA 5&#xff09; AMBA协议简介 ASB&#x…

Capto2024软件怎么下载安装? 【详细安装图文教程】

Capto 2024是一款专为Mac用户设计的屏幕录制编辑软件。无论是想要制作教育视频、工作演示、游戏录制&#xff0c;还是进行简单的屏幕捕捉&#xff0c;Capto 2024都能满足您的需求。接下来&#xff0c;我将详细介绍其主要功能、特点以及使用场景&#xff0c;并为您评价这款软件。…

linux执行ifconfig命令ens33没有显示ip地址解决方法

1.右键启动VMware DHCP和NAT这两个服务 2.执行reboot命令&#xff0c;重启linux。然后再执行ifconfig命令,可以看到inet了&#xff0c;就是ip。xshell也可以连接到主机了。

为什么说这个方向,是网工人最大的机会

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友 都说各行各业早就没有了什么黄金时机&#xff0c;IT行业被称为含金量最高的行业之一&#xff0c;也难逃降薪裁员…

C++ static关键字详解

背景 前段时间初步整理了C中static的相关知识点&#xff0c;以此做个记录。 在C中&#xff0c;static关键字是常见的修饰符。从大方向上static分为两类&#xff1a; 1.类或结构体外的static 2.类或结构体内的static 因此&#xff0c;本文内容的划分如下&#xff1a; 接下来会…

supOS工业操作系统的由来

作为“世界制造工厂”&#xff0c;我国拥有最庞大、最完整的工业企业集群与产业链&#xff0c;其中既有众多全球性制造巨头&#xff0c;又有数以百万计的中小型工厂。但这些企业的制造工厂在推进数字化、网络化、智能化进程时普遍受阻&#xff1a;1&#xff09;系统软件定制程度…

mybatis之特殊SQL的执行

1.1模糊查询 尝试&#xff1a; //模糊查询用户 List<User> getUserByLike(Param("mohu") String mohu);<select id"getUserByLike" resultType"user">select * from user where username like %#{mohu}% </select>Test publ…