Golang入门笔记(15)—— 数组和切片

news2025/1/17 1:11:25

        编程的世界中,或许是因为一次一次的定义变量,维护管理起来都太费劲了,所以推出了数组,将数据用数组的形式管理起来。

        Go的数组和Java的实现机制是不同的,Go语言的数组是作为基本数据类型存在的。所以数组是开辟在栈帧中开辟内存的;在函数参数传递的时候是,也是当作基本数据类型,进行了值传递。

  •        数组

        先不讲那么多七七八八的理论,来段代码直观感受一下Go语言的数组:

package main

import "fmt"

func main() {

	var scores [5]int
	scores[0] = 90
	scores[1] = 91
	scores[2] = 92
	scores[3] = 93
	scores[4] = 94

	//求和,求平均
	sum := 0
	for i := 0; i < len(scores); i++ {
		sum += scores[i]
	}
	fmt.Println(sum)
	fmt.Println(sum / len(scores))

	fmt.Printf("scores 的地址,即第一个空间对应的地址 , %p \n", &scores)
	println("-------------- 16进制,每次大小间隔为8 ------------------")
	fmt.Printf("scores 第0个空间对应的地址 , %p \n", &scores[0])//scores 第0个空间对应的地址 , 0xc000010450
	fmt.Printf("scores 第1个空间对应的地址 , %p \n", &scores[1])//scores 第1个空间对应的地址 , 0xc000010458
	fmt.Printf("scores 第2个空间对应的地址 , %p \n", &scores[2])//scores 第2个空间对应的地址 , 0xc000010460
	fmt.Printf("scores 第3个空间对应的地址 , %p \n", &scores[3])//scores 第3个空间对应的地址 , 0xc000010468
	fmt.Printf("scores 第4个空间对应的地址 , %p \n", &scores[4])//scores 第4个空间对应的地址 , 0xc000010470
}

具体分析:

        16进制数,数组位置,每次大小偏移都是间隔为8,这个8就是每个元素的空间大小。         

关于更多关于数组的认知,可参考之前写的一篇帖子:CSDN

        下面做一个小demo:

package main

import "fmt"

func main() {

	//已知,班级中有10位同学,录入各同学成绩,计算得出总分和平均分。
	var scores [10]int
	//求和,求平均
	sum := 0
	for i := 0; i < len(scores); i++ {
		fmt.Printf("\n 请录入第%v个学生的成绩 \n", i+1)
		fmt.Scanln(&scores[i]) // 录入,改变数组中元素i的值,通过 & 绑定到哪个地址。
		sum += scores[i]
	}
	fmt.Println("总分:", sum)
	fmt.Println("平均分", sum/len(scores))

}

        数据遍历方式,除了使用上面代码中的以索引下标进行普通遍历外,还可以使用for range 遍历,for range 可以遍历数组,切片,字符串,map 以及通道,for range语法上类似于其他编程语法的foreach语句,形式如下:

for key,val:= range collection{
    ...
}

           代码如下:

package main

func main() {

	var scores [5]int
	scores[0] = 90
	scores[1] = 91
	scores[2] = 92

	for key, value := range scores {
        //key,value 属于当次循环的局部变量。
		println("[", key, "] ==> ", value)
	}


	for key, value := range scores {
        //key,value 属于当次循环的局部变量。
		println("[", key, "] ==> ", value)
	}

    // 如果用不到key,使用 下划线 “_” 可以忽略。
	for _, value := range scores {
		println( "==> ", value)
	}
}

     key,value 属于当次循环中的局部变量。

数组的初始化方式:

第一种:var 类型自己推断。

	var scores = [5] int {1,3,5,7,9}

第二种:事先不知道开辟多大空间。

	var scores = [...]int{1, 3, 5, 7, 9}

第三种:根据下标逐一赋值

	var scores = [...]int{0: 70, 2: 30, 3: 99, 4: 100}

数组的注意事项:

1.数组的长度属于类型的一部分,相当于动态数组的类属性。

	var a = [...]int{0: 70, 2: 30, 3: 99, 4: 100}
	fmt.Printf(" 数组类型:%T", a) // [5]int

2. Java中数组属于引用类型,但是在Go语言中,数组属于值类型的,默认情况下,按值传递,因此会进行值拷贝。如果想在其他函数中,去修改原来的数组,可以通过指针的方式进行引用传递。


import "fmt"

func main() {

	var a = [...]int{0: 0, 1: 1, 2: 2, 3: 3, 4: 4}
	modify(a)
	fmt.Println(a)

	modifyPlus(&a) //传入地址
	fmt.Println(a)

}

func modify(arr [5]int) {  
	arr[0] = -999
}

func modifyPlus(arr *[5]int) { // star在类型Type上,means This‘s pointer the address (ptr)
	(*arr)[0] = -999 // 
}

        分析:当goroutine(轻量的go线程) 的 active-frame活动栈帧  从main函数 运行 到modifyPlus 函数的 栈帧时,通过 *pointerTheAddress变量ptr的方式,进行引用传递的方式,完成了对该内存数据的重新赋值;而modify 是默认的值传递,是值拷贝,操作不是同一块内存。

二维数组 Two Dimensional Array (注音:dimensional大爱闷声捞 恶ray )

        定义二维数组  var twoDimensionalArr  [2][3] int16  

        2个3长度的数组,默认初始值 [0,0,0],[0,0,0] ,内存分配,如下图:

var arr [2][3] int16 内存分配 示意图

        Anyhow无论 它是二维也好,N维也罢,在内存中都是一个连续的内存空间,就是在连续的数组中不断的拆分内存。 二维 [2][3] 即 开辟2*3 =6个类型大小。三维[2][3][4],即2*3*4=24 个类型大小。

package main

import (
	"fmt"
)

func main() {

	var a [2][3]int
	a[0][1] = 22
	fmt.Printf("\n\t a ↓ \n  %v \n", a) //  [ [0 22 0]  [0 0 0] ]

	var init2dArray [2][3]int = [2][3]int{{1, 2, 3}, {2, 3, 4}}
	fmt.Printf("二维数组的初始化操作 ==>  %v \n", init2dArray)

	fmt.Println("--------- 遍历方式1 普通for循环 ----------")
	for i := 0; i < len(init2dArray); i++ {
		for j := 0; j < len(init2dArray[i]); j++ {
			fmt.Println(init2dArray[i][j])
		}
	}

	fmt.Println("--------- 遍历方式2 for range循环 ----------")
	for outerKey, outerValue := range init2dArray {
		//fmt.Println(outerKey, outerValue)
		for innerKey, innerValue := range outerValue {
			fmt.Printf("arr[%v][%v]=[%v] \t", outerKey, innerKey, innerValue)
		}
		println()
	}

}

        同样,Go和Java一样,都支持多维数组:

package main

import (
	"fmt"
)

func main() {
	var a [2][3][4][5]int
	fmt.Printf("a ==>\n  %v ", a)
}
  •         切片

        切片可以算是对数组的扩展,数组的长度是固定的,所以在Go语言的代码的出现频率不高,而切片是一种建立在数组的基础上做了一层封装,提供了更加强大的功能。正因为如此,所以切片是一种引用类型。切片slice 是对数组一个连续片段的引用,所以切片是一个引用类型,对切片索引的操作,可以改变原来的数组索引上的元素;具体形式:[start:end],这个片段是由起始切点偏移索引和终止切点偏移索引构成,可以是整个数组,或者是部分数组,但是注意一点:切点偏移索引不能越界,切片感觉类似于Java的封装的ArrayList动态数组。

        切片三个要素之我的理解:切片的地址(首元素的地址?),实际元素大小size 和 capacity总的容量;

内存中 原数组 intArr 和切片 示意图

         

        切片定义的三种方式:

方式1:定义一个切片,然后让切片去 切(引用)一个以及创建好的数组。

	var strings []string = []string{"a", "b", "c", "d", "e", "f", "g", "h"}
	var stringSlice []string
	stringSlice = strings[2:6]

方式2:通过内置的make函数来创建切片。

基本语法:var 切片变量名 [] T类型 = make([]T类型,size,capacity);

         make([]T, size, cap)  底层数组的指针、切片的大小( len )和切片的容量(cap)。

	fmt.Println("-----------  make([]T, size, cap) --------------")
	var bridgeSlice []int = make([]int, 2, 10) 
	fmt.Println(len(bridgeSlice))              // len表示切片存储元素的长度
	fmt.Println(cap(bridgeSlice))              // cap表示最大可以存储的容量
	//ps 底层数组对外不可见,不能直接操作数组,通过操作slice切片变量桥接到数组。
	bridgeSlice[0] = 0
	bridgeSlice[1] = 1

        点评:底层数组对外不可见,不能直接操作数组,通过操作slice切片变量桥接到数组。

方式3:定义一个切片,直接就指定具体的数组,使用原理类似make方式。

	sliceDefine3 := []string{"a", "b", "c"}
	fmt.Println(len(sliceDefine3)) // len表示切片存储元素的长度
	fmt.Println(cap(sliceDefine3)) // cap表示最大可以存储的容量

        点评:质疑一下,我感觉和数组没啥区别呀,连实际元素len和capacity 都一样。不过,学习阶段,被动接受吧,别人说是啥,那就是啥。就算错了,以后再改了这段文字就好了。不追求完美,追求完美本身就是不完美。

参考代码:

	fmt.Println("----------- make函数  make([]T, size, cap) --------------")
	var bridgeSlice []int = make([]int, 2, 10) //底层数组的指针、切片的大小( len )和切片的容量(cap)。
	fmt.Println(len(bridgeSlice))              // len表示切片存储元素的长度
	fmt.Println(cap(bridgeSlice))              // cap表示最大可以存储的容量
	//ps 对外不可见,不能直接操作数组,通过操作slice切片变量桥接到数组。
	bridgeSlice[0] = 0
	bridgeSlice[1] = 1

切片的遍历:和数组遍历方式一样,普通for循环和for...range循环都可以。代码略,参考上面数组遍历。

切片的注意事项:

1,切片定义后,不能直接使用,需要让其引用到一个数组 或 make一个空间供切片使用。

2.切片不能越界。

3.切片可以继续切片。

4.切片的capacity 可以动态增长,容量不够,底层会创建一个新数组,然后指向新数组。该新数组不能直接维护,通过切片间接维护。如果你要想给原来切片append函数追加给原来的slice,并赋值给slice。

slice = append(slice,1,2,3)

5.切片的拷贝。copy函数,第一个参数: destination目标,第二个参数:source 源。

fmt.Println("----------- copy函数 --------------")
	var x1 []int = []int{1, 2, 3, 4, 5}
	var x2 []int = make([]int, 10)
	copy(x2, x1)
	fmt.Println(x2)

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

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

相关文章

Golang Web开发一键生成各层级模板代码

文章目录go_project_quickstart快速开始要求安装项目实现架构设计代码逻辑统一的调用逻辑代码复用每次写web项目&#xff0c;模板都是统一的&#xff0c;每次都要写大量冗余的代码会很烦&#xff0c;在Java中有很多逆向生成的工具&#xff0c;而Go语言我找了很久&#xff0c;也…

手把手搭建springboot项目,并测试springDataJPA

这篇文章记录了搭建springboot项目并测试springDataJPA的过程&#xff0c;接下来一起看看吧。 1.访问阿里云java脚手架网站 点击访问 2.按照下图勾选并获取代码 3.将获取到的代码解压到idea工作空间。 下图的JPAdemo就是我的项目 4.打开idea&#xff0c;导入项目 5.在pom…

【Redis】| 01 | Redis 可视化工具RedisInsight

目录1 RedisInsight 简介2 RedisInsight 安装2.1 安装2.1.1 软件安装2.1.1.1 下载 RedisInsight 软件包2.1.1.2 安装命令2.1.1.3 配置环境变量2.1.1.4 启动服务2.1.2 Kubernetes 安装2.1.2.1 创建 RedisInsight 的 yaml 文件2.1.2.2 启动3.RedisInsight 使用3.1 安装redis3.1.1…

Jacobi迭代的MPI进阶——计算通信重叠和虚拟进程的使用

1:条形分割的几种策略 这里先放Makefile和run.slurm Makefile CC = mpicc FLAGS = -O3 -Wall OBJ = *.o EXE = hang hangstartall Ihang xunihang qipan srqipan Isrqipan qipanendall: ${EXE}hang: hang.c $(CC) -o $@ $^ $(FLAGS)

信息安全结业复习题(选择 + 填空 + 简答 + 计算 + 设计 )含历年考题

这里写目录标题客观题知识点简答题计算题设计题客观题知识点 考过填空 密码学是保障信息安全的核心、信息安全是密码学研究和发展的目标 保证数字信息机密性的最有效方法是使用密码算法对其进行加密&#xff08;对称和非对称&#xff09; 保证信息完整性的有效方法是利用hash…

SQL Server全套教程(基于SQL语句----续更中)

SQL Server全套教程全程干货1. 数据库的基础操作1.1.0 创建数据库1.1.1 查看及修改数据库1.1.3 分离、附加和删除数据库2.数据库表的相关操作2.1.0 常用数据类型2.1.1 表结构的创建2.1.2 表结构的查看及修改1. 数据库的基础操作 1.1.0 创建数据库 数据库创建语法 -- 创建数据…

MicroPython-On-ESP8266——8x8LED点阵模块(2)使用74HC595驱动

MicroPython-On-ESP8266——8x8LED点阵模块&#xff08;2&#xff09;使用74HC595驱动 1. 使用74HC595驱动的原理 1.1. 基础回顾 上篇我们学习了8x8LED点阵屏的电路基础知识和驱动的原理&#xff0c;见 8x8LED点阵模块&#xff08;1&#xff09;驱动原理 里面也提到了&…

基于ssm+Javaweb的OA小型企业资源管理系统-计算机毕业设计

小型OA企业资源管理系统基于SSM(SpringSpringMVCMyBatis)框架,适用于毕业设计&#xff0c;采用javaweb,基于B/S模式,Myeclipse或者eclipse idea为开发工具,mysql数据库,主要包括登录模块、人事管理模块、公告管理模块、产品管理模块、和退出模块等多个模块。 本系统主要包含了…

MySQL高级篇知识点——主从复制

目录1.主从复制概述1.1.如何提升数据库并发能力1.2.主从复制的作用2.主从复制的原理2.1.原理剖析2.2.复制的基本原则3.一主一从架构搭建3.1.准备工作3.2.主机配置文件3.3.从机配置文件3.4.主机&#xff1a;建立账户并授权3.5.从机&#xff1a;配置需要复制的主机3.6.测试3.7.停…

tensorflow2.x --------------------DenseNet-----------------------------

用tensorflow2.4实现了DenseNet-121,训练基于ImageNet图像数据集&#xff0c;图片输入大小为 224x224 。网络结构采用包含4个DenseBlock的DenseNet-BC&#xff0c;每个DenseNet-BC由若干个 BNReLU1x1 ConvBNReLU3x3 Conv&#xff08;Dense_layer)且每个DenseBlock的特征图大小分…

听我劝,自学游戏建模真的很难

我的个人建议一直是偏向不要自学建模的&#xff08;特别是零基础&#x1f923;&#xff09;&#xff0c;学习3D游戏建模除了单纯需要为爱发电还需要能够自行✅掌握软件操作技巧和✅纠错改正&#xff0c;后者都是自学非常❌难做到的&#x1f62d; 除此之外&#xff0c;还有以下…

详解Unity中的Nav Mesh新特性|导航寻路系统 (二)

前言 第一篇我们简要概述了新版NavMesh的一些新增功能&#xff0c;以及旧版的对比。本篇我们来讲一讲NavMeshSurface、NavMeshLink这两个组件的参数以及如何应用&#xff0c;接下来就进入正题吧。 本系列提要 Unity新版NavMesh专题博客共分成三篇来讲解&#xff1a; 【本篇为…

Golang入门笔记(最后一章 17 封版)—— 映射map

映射 (map) 作为一个常用的类型&#xff0c;Go语言已为我们开发者内置了map类型。 基本语法&#xff1a; var 变量名 map [keyT类型] valueT类型 这里T就是一个类型代表&#xff08;我这么写&#xff0c;有点受到了Java的泛型影响&#xff09;&#xff0c;key的类型通常为str…

【20-业务开发-基础业务-商品模块-分类管理-前端展示后端具有层级关系的目录数据-商品系统三级分类的逻辑删除前后端代码实现】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

JUC线程池——newSingleThreadExecutor源码解析JDK提供线程池ThreadPoolExecutor执行任务流程解析

newSingleThreadExecutor源码解析&&JDK提供线程池ThreadPoolExecutor执行任务流程解析测试代码核心代码解析ThreadPoolExecutor内部类&#xff1a;Worker解析调试台线程切换到执行异步任务的线程ThreadPoolExecutor&#xff1a;getTask()LinkedBlockingQueue&#xff1…

shell-函数

函数介绍 shell中有系统函数&#xff0c;也可以自定义函数 系统函数 basename basename [pathname] [suffix] 返回完整路径最后的/的部分&#xff0c;常用于获取文件名 basename命令会删掉所有的前缀包括最后一个/字符&#xff0c;然后将字符串显示出来 suffix为后缀&#…

java计算机毕业设计专业招聘网站(附源码、数据库)

java计算机毕业设计专业招聘网站&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技…

从零搭建个人博客项目并通过github部署上线

文章目录一、环境准备二、创建hexo博客项目1.全局安装hexo-cil工具2.新建hexo项目3.启动项目三、部署上线1.新建github仓库2.修改配置项3.部署项目一、环境准备 1.Node.js (版本需不低于 10.13) 2.Git https://hexo.io/zh-cn/ hexo博客官方文档 二、创建hexo博客项目 1.全局安…

dhtmlx甘特图marker不随小时移动

dhtmlx甘特图marker是什么&#xff1f; 就是一个跟着日期变化的标记&#xff0c;如下图所示 这段代码是用来调整标记的样式&#xff0c;展示文本的关键代码&#xff0c;如要配置今日标记&#xff0c;需在plugins添加maker后加上这段代码 start_date是用来获得日期的&#xf…

Ubuntu20单机搭建MongoDB4.2集群详细

文章目录 MongoDB文件下载选择你的服务器的安装路径配置文件启动服务集群配置MongoDB文件下载 curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.23.tgz # 直接将版本号4.2.23换成自己需要的版本号即可 将文件下载到你的服务路径选择你的服务器…