gogo语言学习笔记三

author author     2022-08-19     776

关键词:

7、数组:

几乎是最常用的数据类型了。。。

数组就是指一系列同一类型数据 的集合。数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数 组的长度。

常规的数组声明方法:

[32]byte   // 长度为32的数组,每个元素为一个字节
[2*N] struct {x , y int32} //复杂类型数组
[1000]*float32 //指针数组
[3][5]int //二维数组
[2][2][2]float64   // 等同于[2]([2]([2]float64))

在Go语言中,数组长度在定义后就不可更改,在声明时长度可以为一个常量或者一个常量 表达式(常量表达式是指在编译期即可计算结果的表达式)。数组的长度是该数组类型的一个内 置常量,可以用Go语言的内置函数len()来获取。下面是一个获取数组arr元素个数的写法:
arrLength := len(arr)

a、元素访问

可以使用数组下标来访问数组中的元素。数组下标从0开始,len(array)-1 则表示最后一个元素的下标。下面的示例遍历整型数组并逐个打印元素内容:

for i := 0; i < len(array); i++ { 
    fmt.Println("Element", i, "of array is", array[i])
}

还可以用range遍历

for i, v := range array {
    fmt.Println("Array element[", i, "]=", v)
}

range具有两个返回值,第一个返回值是元素的数组下标,第二个返回值是元素的值。

b、值类型

需要特别注意的是,在Go语言中数组是一个值类型(value type)。所有的值类型变量在赋值和作为参数传递时都将产生一次复制动作。
如果将数组作为函数的参数类型,则在函数调用时该 参数将发生数据复制。因此,在函数体中无法修改传入的数组的内容,因为函数内操作的只是所 传入数组的一个副本。

举例:

package main
import "fmt"
func modify(array [10]int) {
    array[0] = 10 // 试图修改数组的第一个元素 
  fmt.Println("In modify(), array values:", array) } func main() { array := [5]int{1,2,3,4,5} // 定义并初始化一个数组 modify(array) // 传递给一个函数,并试图在函数体内修改这个数组内容 fmt.Println("In main(), array values:", array) }

该程序的执行结果为:
In modify(), array values: [10 2 3 4 5]
In main(), array values: [1 2 3 4 5]

从执行结果可以看出,函数modify()内操作的那个数组跟main()中传入的数组是两个不同的实 例。那么,如何才能在函数内操作外部的数据结构呢?可以用数组切片功能来达成这个目标。

8、数组切片:

在前一节里我们已经提过数组的特点:数组的长度在定义之后无法再次修改;数组是值类型, 每次传递都将产生一份副本。显然这种数据结构无法完全满足开发者的真实需求。
不用失望,Go语言提供了数组切片(slice)这个非常酷的功能来弥补数组的不足。
初看起来,数组切片就像一个指向数组的指针,实际上它拥有自己的数据结构,而不仅仅是 个指针。数组切片的数据结构可以抽象为以下3个变量:
? 一个指向原生数组的指针;

? 数组切片中的元素个数;

? 数组切片已分配的存储空间。
从底层实现的角度来看,数组切片实际上仍然使用数组来管理元素,因此它们之间的关系让 C++程序员们很容易联想起STL中std::vector和数组的关系。基于数组,数组切片添加了一系 列管理功能,可以随时动态扩充存放空间,并且可以被随意传递而不会导致所管理的元素被重复 复制。

a、创建数组切片
创建数组切片的方法主要有两种——基于数组和直接创建,下面我们来简要介绍一下这两种方法。
? 基于数组
数组切片可以基于一个已存在的数组创建。数组切片可以只使用数组的一部分元素或者整个数组来创建,甚至可以创建一个比所基于的数组还要大的数组切片。
代码清单2-1(slice.go)演示了如何基于一个数组的前5个元素创建一个数组切片。

package main
import "fmt"
func main() {
    // 先定义一个数组
    var myArray [10]int = [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} // 基于数组创建一个数组切片
    var mySlice []int = myArray[:5]
    fmt.Println("Elements of myArray: ") 
    for _, v := range myArray {
       fmt.Print(v, " ")
    }
    fmt.Println("
Elements of mySlice: ")
    for _, v := range mySlice { 
      fmt.Print(v, " ")
    }
    fmt.Println()
}    

运行结果为:
Elements of myArray:
1 2 3 4 5 6 7 8 9 10
Elements of mySlice:
1 2 3 4 5 

Go语言支持用myArray[first:last]这样的方式来基于数组生成一 个数组切片,而且这个用法还很灵活,比如下面几种都是合法的。
基于myArray的所有元素创建数组切片:
mySlice = myArray[:]
基于myArray的前5个元素创建数组切片:
mySlice = myArray[:5]
基于从第5个元素开始的所有元素创建数组切片:
mySlice = myArray[5:]

? 直接创建( make() )

并非一定要事先准备一个数组才能创建数组切片。Go语言提供的内置函数make()可以用于
灵活地创建数组切片。下面的例子示范了直接创建数组切片的各种方法。
创建一个初始元素个数为5的数组切片,元素初始值为0:
mySlice1 := make([]int, 5)
创建一个初始元素个数为5的数组切片,元素初始值为0,并预留10个元素的存储空间:
mySlice2 := make([]int, 5, 10)
直接创建并初始化包含5个元素的数组切片:
mySlice3 := []int{1, 2, 3, 4, 5}
事实上还会有一个匿名数组被创建出来,只是不需要我们来操心而已。

b、元素遍历

操作数组元素的所有方法都适用于数组切片,比如数组切片也可以按下标读写元素,用len() 函数获取元素个数,并支持使用range关键字来快速遍历所有元素。
传统的元素遍历方法如下:

for i := 0; i <len(mySlice); i++ { 
    fmt.Println("mySlice[", i, "] =", mySlice[i])
} 

使用range关键字可以让遍历代码显得更整洁。range表达式有两个返回值,第一个是索引,

第二个是元素的值:

for i, v := range mySlice { 
    fmt.Println("mySlice[", i, "] =", v)
} 

对比上面的两个方法,我们可以很容易地看出使用range的代码更简单易懂。

c、动态增减元素

  可动态增减元素是数组切片比数组更为强大的功能。与数组相比,数组切片多了一个存储能 力(capacity)的概念,即元素个数和分配的空间可以是两个不同的值。合理地设置存储能力的 值,可以大幅降低数组切片内部重新分配内存和搬送内存块的频率,从而大大提高程序性能。
  假如你明确知道当前创建的数组切片最多可能需要存储的元素个数为50,那么如果你设置的 存储能力小于50,比如20,那么在元素超过20时,底层将会发生至少一次这样的动作——重新分 配一块“够大”的内存,并且需要把内容从原来的内存块复制到新分配的内存块,这会产生比较 明显的开销。给“够大”这两个字加上引号的原因是系统并不知道多大才是够大,所以只是一个 简单的猜测。比如,将原有的内存空间扩大两倍,但两倍并不一定够,所以之前提到的内存重新 分配和内容复制的过程很有可能发生多次,从而明显降低系统的整体性能。但如果你知道最大是 50并且一开始就设置存储能力为50,那么之后就不会发生这样非常耗费CPU的动作,从而达到空间换时间的效果。
  数组切片支持Go语言内置的cap()函数和len()函数,代码清单2-2( slice2.go )简单示范了这两个内置函数的用法。可以看出,cap()函数返回的是数组切片分配的空间大小,而len()函数返回的是 数组切片中当前所存储的元素个数。

package main
import "fmt" 
func main() {
    mySlice := make([]int, 5, 10)
    fmt.Println("len(mySlice):", len(mySlice))
    fmt.Println("cap(mySlice):", cap(mySlice)) 
}

该程序的输出结果为:
len(mySlice): 5
cap(mySlice): 10

如果需要往上例中mySlice已包含的5个元素后面继续新增元素,可以使用append()函数。 下面的代码可以从尾端给mySlice加上3个元素,从而生成一个新的数组切片:

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

函数append()的第二个参数其实是一个不定参数,我们可以按自己需求添加若干个元素,
甚至直接将一个数组切片追加到另一个数组切片的末尾:

mySlice2 := []int{8, 9, 10}
// 给mySlice后面添加另一个数组切片
mySlice = append(mySlice, mySlice2...)

需要注意的是,我们在第二个参数mySlice2后面加了三个点,即一个省略号,如果没有这个省 略号的话,会有编译错误,因为按append()的语义,从第二个参数起的所有参数都是待附加的元素。因为mySlice中的元素类型为int,所以直接传递mySlice2是行不通的。加上省略号相当于把mySlice2包含的所有元素打散后传入。

数组切片会自动处理存储空间不足的问题。如果追加的内容长度超过当前已分配的存储空间(即cap()调用返回的信息),数组切片会自动分配一块足够大的内存。

d、基于数组切片创建数组切片

类似于数组切片可以基于一个数组创建,数组切片也可以基于另一个数组切片创建。下面的 例子基于一个已有数组切片创建新数组切片:

oldSlice := []int{1, 2, 3, 4, 5}
newSlice := oldSlice[:3] // 基于oldSlice的前3个元素构建新数组切片

e、内容复制

数组切片支持Go语言的另一个内置函数copy(),用于将内容从一个数组切片复制到另一个 数组切片。如果加入的两个数组切片不一样大,就会按其中较小的那个数组切片的元素个数进行 复制。下面的示例展示了copy()函数的行为:

slice1 := []int{1, 2, 3, 4, 5} 
slice2 := []int{5, 4, 3}
copy(slice2, slice1) // 只会复制slice1的前3个元素到slice2中 
copy(slice1, slice2) // 只会复制slice2的3个元素到slice1的前3个位置

未完待续。。。  

  

 

  

  

 

 

  

 

 

 

  

  

  

  

gogo语言学习笔记二

基本类型:布尔型:boolean整型:int8,byte,int16,int,uint,uintptr等浮点型:float32,float64复数类型:complex64,complex128字符串型:string字符型:rune错误类型:error复合类型:指针:pointer数组:array切片:slice字典:map通道:chan结构体:struct... 查看详情

gogo语言学习笔记四

 流程控制1、条件语句举个栗子:ifx>5{return1;}else{return0;}注意:?条件语句不需要使用括号将条件包含起来();?无论语句体内有几条语句,花括号{}都是必须存在的;?左花括号{必须与if或者else处于同一行;?在if之后,条件语句之前,... 查看详情

gogo语言学习笔记一

a、为何学习GO语言?从个人角度来看,第一是被GO语言传说中的那样超高的开发效率和运行效率所吸引;第二是GO语言在语言层面支持并发,这在现在的编程业务中是很方便的;第三是由于前两点,我觉得以后GO会火起来;最后一... 查看详情

gogo语言环境安装(代码片段)

...工具  1、Linux(CentOS7.4版)  2、go1.11.2.linux-amd64.tarGo语言环境安装  1、下载安装包    安装包下载地址为:https://golang.org/dl/。      如果打不开可以使用这个地址:https://golang.google.cn/dl/。      2、将... 查看详情

numpy学习笔记三股票价格

NumPy学习笔记三股票价格《NumPy学习笔记》系列将记录学习NumPy过程中的动手笔记,前期的参考书是《Python数据分析基础教程NumPy学习指南》第二版、《数学分析》第四版(华东师范大学数学系)、《概率论与数理统计》(陈希孺... 查看详情

学习笔记(三)

OpenSCManager:functionOpenSCManager(lpMachineName,lpDatabaseName:PChar;dwDesiredAccess:DWORD):SC_HANDLE;stdcall;OpenSCManager,函数建立了一个到服务控制管理器的连接,并打开指定的数据库。参数lpMachineName  指向零终止字符串,命名为目标计算机。如... 查看详情

javaweb学习笔记(三)

#MyEclipseTomcatv7.0启动时,Console提示:警告:[SetPropertiesRule]{Server/Service/Engine/Host/Context}Settingproperty‘source‘to‘org.eclipse.jst.jee.server:learnStruts02‘didnotfindamatchingproperty.根据“Serv 查看详情

mybatis学习笔记三(关联关系)

  学习mybatis的关联关系,主要注解在代码上,这里不做解释。配置文件一样的就不贴了1.关联关系表创建(学生对应老师多对一)  学生老师表  2.表对应的实体类packagecom.home.entity;/***此类是:学生*@authorhpc*@2017年1月1... 查看详情

java笔记学习三

学习代码记录/** *随机生成指定长度的字符串 *  *@param *@paramlengthOfString *@return纯字母字符串 */ publicstaticStringgetRndStrByLen(intlengthOfString){ inti,count=0; finalStringchars="A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q 查看详情

学习笔记三

使用puTTY和Xshell远程连接Linux以及密钥认证使用puTTY远程连接Linux首先,安装puTTY,它是一个免费的开源的软件,且操作和配置非常简单易用,下载地址:www.chiark.greenend.org.uk下载安装包putty-0.70-installer.msi(下载32位就可以了,64位... 查看详情

学习笔记三

使用puTTY和Xshell远程连接Linux以及密钥认证使用puTTY远程连接Linux首先,安装puTTY,它是一个免费的开源的软件,且操作和配置非常简单易用,下载地址:www.chiark.greenend.org.uk下载安装包putty-0.70-installer.msi(下载32位就可以了,64位... 查看详情

redis学习笔记三

一、redis复制数据库复制指的是发生在不同数据库实例之间,单向的信息传播的行为,通常由被复制方和复制方组成,被复制方和复制方之间建立网络连接,复制方式通常为被复制方主动将数据发送到复制方,复制方接收到数据... 查看详情

nodejs学习笔记三(用户注册登录)

1.定接口   /user接口       输入  act=reg&user=aaa&pass=123456       输出  {"ok":false,"msg":"原因" 查看详情

deeplearning(深度学习)学习笔记整理系列三

DeepLearning(深度学习)学习笔记整理系列 声明:1)该DeepLearning的学习系列是整理自网上很大牛和机器学习专家所无私奉献的资料的。具体引用的资料请看参考文献。具体的版本声明也参考原文献。2)本文仅供学术交流,非... 查看详情

华为防火墙学习笔记三

FW防火墙 外部管理的配置:1.配置untrust区访问local区域【便于telnet远程管理】【fw1】firewallpasket-filterdefaultpermitinterzoneuntrustlocaldirectioninbound      direction   [d??rek 查看详情

网页开发学习笔记三:html选择器

选择器是一个选择标签的过程标签选择器  标签{属性:值;属性:值;}<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>Document</title><styletype="text/css">/*样式表内容*/div{font-size:50px;colo 查看详情

科目三学习笔记

考试项目:模拟灯光->起步->靠边停车->左转->右转出路口->直行通过路口,公交站,左转->直行->左转->加减档->直行->掉头->超车->变更车道注意事项:起步==踩离合刹车,挂1档,松手刹,打左灯,按喇叭靠边停车==... 查看详情

node学习笔记三

global  --类似与客户端javascript运行环境中的windowprocess  --用于获取当前node进程信息,一般用于获取环境变量之类的信息console  --node中内置的console模块,提供操作控制台的输入输出功能,常见是用方式与客户端类似 nod... 查看详情