一、数组

1.什么是数组?

  1.数组是一系列同一类型数据的集合

  2.数组中包含的每个数据被称为数组元素

  3.一个数组中包含的元素个数成为数组长度

  4.数组的长度是固定的

  5.一个数组可以由零个或者多个元素组成    

2.数组的申明

var arr [10]int           //10个元素的整型数组

var ptrs [5]*float64  //5个元素的指针数组,每个指针都指向float64类型 

var points [8]struct{ x, y int }  //8个元素的结构体类型

var arry [2][3]int               //2*3的二维整型数组 

a := [3]int{1, 2, 3} // 长度为3的数组

b := [5]int{1, 2, 3} //长度为10,前三个元素为1、2、3,其它默认为0

c := [...]int{4, 5, 6} //长度3的方式,Go自动计算长度

r := [...]int{9: 6}    //长度为10,最后一个元素的值为6,其它默认为0

arr2 := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}//二维数组

数组的申明

  在Go语言中,数组长度在定义后就不可更改,在声明时长度可以为一个常量或者一个常量表达式。

  

3.数组的初始化

//申明数组
var a [5]byte //长度为5的数组,每个元素为一个字节
var d [2][3]int //二维数组 //初始化数组
a = {'1','2','3'}
d = {{1,2,3},{4,5,6}}

先申明再初始化

a := [3]byte{'1', '2', '3'} //声明并初始化一个长度为3的byte数组
a := [...]byte{'1', '2', '3'} //可以省略长度而采用`...`的方式,Go会自动根据元素个数来计算长度
d := [2][3]int{[3]int{1,2,3},[3]int{4,5,6}}
d := [2][3]int{{1,2,3},{4,5,6}} //如果内部的元素和外部的一样,那么上面的声明可以简化,直接忽略内部的
类型

直接申明并初始化

4.数组元素访问

  1.可以使用数组下标来访问数组中的元素

  2.数组下标从0开始

  3.len(arr)-1则表示最后一个元素的下标

package main

import (
"fmt" ) func main() {
var result int
arr := [...]int{1, 2, 3, 4, 5} len := len(arr) //len获取数组长度 fmt.Println("修改前:", arr) arr[0] = 100 //下标访问数组元素 result = arr[3] //取出下标为3的元素并赋值 fmt.Println("修改后:", arr) fmt.Println("数组长度:", len) fmt.Println("方位下标为三的元素:",result)
} //运行结果
//修改前: [1 2 3 4 5]
//修改后: [100 2 3 4 5]
//数组长度: 5
//方位下标为三的元素: 4

元素访问

package main

import(
"fmt"
) func main(){
arr := [...]int {9: 1}
fmt.Println(arr)
fmt.Println(len(arr))
} //运行结果
//[0 0 0 0 0 0 0 0 0 1]
//10

计算数组长度

package main

import(
"fmt"
) func main(){
arr := [5]int {1, 2, 3, 4, 5}
for i := 0; i < len(arr); i++{
fmt.Printf("arr[%d]=%d\n", i, arr[i])
}
} //运行结果
//arr[0]=1
//arr[1]=2
//arr[2]=3
//arr[3]=4
//arr[4]=5

普通访问方式,for

package main

import(
"fmt"
) func main(){
arr := [5]int {1, 2, 3, 4, 5}
for i, v := range(arr) {
fmt.Printf("arr[%d]=%d\n", i, v)
}
} //运行结果
//arr[0]=1
//arr[1]=2
//arr[2]=3
//arr[3]=4
//arr[4]=5

通过range访问

5.数组的传递

  1.数组作为函数的参数仍然是值传递(值传递是复制数组给函数,传递后数组跟原数组没有关系)

  2.虽然可以使用数组的指针来代替,但是改变不了数组长度。(可以改变数组内的值,但是不能改变数组的长度)

package main

import "fmt"

func main() {
arr1 := [5]int{1, 2, 3, 4, 5}
fmt.Println("交换前arry1= " ,arr1) swap(arr1 ) fmt.Println("交换后arry1= " ,arr1) }
func swap(a [5]int) {
arr3 := a
fmt.Println("值传递交换前arr3= ",arr3) c := arr3[0]
arr3[0] = arr3[4]
arr3[4] = c
fmt.Println("值传递交换后arr3= ",arr3) } //运行结果
//交换前arry1= [1 2 3 4 5]
//值传递交换前arr3= [1 2 3 4 5]
//值传递交换后arr3= [5 2 3 4 1]
//交换后arry1= [1 2 3 4 5]

数组的值传递

package main

import "fmt"

func main() {
arr1 := [5]int{1, 2, 3, 4, 5}
fmt.Println("交换前arry1= " ,arr1) swap_pointer(&arr1 ) fmt.Println("交换后arry1= " ,arr1) } func swap_pointer(a *[5]int) {
var arr3 *[5]int
arr3 = a
fmt.Println("指针传递交换前arr3= ",arr3) c := arr3[0]
arr3[0] = arr3[4]
arr3[4] = c
fmt.Println("指针传递交换后arr3= ",arr3)
} //运行结果
//交换前arry1= [1 2 3 4 5]
//指针传递交换前arr3= &[1 2 3 4 5]
//指针传递交换后arr3= &[5 2 3 4 1]
//交换后arry1= [5 2 3 4 1]

数组的指针传递

6.数组的比较

  1.如果数组元素的类型是可比较的,那么这个数组也是可的比较

  2.只有数组的所有元素都相等数组才是相等的。

  3.由于长度也是数组类型的一部分,所以长度不同的数组是不等的。

  4.数组可遍历、可修改,是否可比较,由数组元素决定。

  5.%T用于显示一个值对应的数据类型。

7.数组的局限性

  1.数组的长度在定义之后无法修改。

  2.数组是值类型,每次传递都将产生一份副本。

  3.显然这无法满足开发者的某些需求。

二、切片(slice)

1.什么是切片?

  1.切片(Slice)是一个拥有相同类型元素的可变长度的序列。

  2.Go语言切片的内部结构包含地址、大小和容量。

  3.切片一般用于快速地操作一块数据集合。

  4.slice 总是指向底层的一个 array。

  5.slice本身不是数组,slice 是一个指向 array的指针。

              切片结构和内存分布示意图

2. 从数组或者一个切片中生成一个切片

  slice [开始位置:结束位置:容量]

    a. slice 表示目标切片对象

    b. 开始位置对应目标切片对象的索引

    c. 结束位置对应目标切片的结束索引

package main

import "fmt"

func main() {

    var a = [5]int{1,2,3}
var c []int
c = a[1:4:5] fmt.Println("c的长度为:%d",len(c))
fmt.Println("c的容量为:%d",cap(c))
fmt.Printf("c的类型:%T",c)
} //运行结果
//c的长度为:%d 3
//c的容量为:%d 4
//c的类型:[]int

从数组或切片中生成切片

  从数组或切片生成新的切片拥有如下特性

    a.取出的元素数量为:结束位置-开始位置

    b.取出元素不包含结束位置对应的索引,切片最后一个元素使用 slice[len(slice)] 获取

    c.当缺省开始位置时,表示从连续区域开头到结束位置

    d.当缺省结束位置时,表示从开始位置到整个连续区域末尾

    e.两者同时缺省时,与切片本身等效

    f.两者同时为0时,等效于空切片,一般用于切片复位

    (ps:根据索引位置取切片 slice 元素值时,取值范围是(0~len(slice)-1),超界会报运行时错误。生成切片时,结束位置可以填写 len(slice) 但不会报错。)

3.直接申明新切片

  每一种类型都可以拥有其切片类型,表示多个类型元素的连续集合。

var name []T

//name 表示切片类型的变量名。
//T 表示切片类型对应的元素类型。
package main

import "fmt"

func main() {

    // 声明字符串切片
var strList []string
// 声明整型切片
strList = []string{"asa","esd"}
var numList []int
// 声明一个空切片
numListEmpty := []int{1,2,3}
// 输出3个切片
fmt.Println(strList, numList, numListEmpty)
// 输出3个切片大小
fmt.Println(len(strList), len(numList), len(numListEmpty))
// 切片判定空的结果
fmt.Println(strList == nil)
fmt.Println(numList == nil)
fmt.Println(numListEmpty == nil) } //运行结果
//[asa esd] [] [1 2 3]
//2 0 3
//false
//true
//false

直接声明新的切片

  ps:  1. 切片是动态结构,只能与nil判定相等,不能互相判等。

    2. 声明新的切片后,可以使用append() 函数来添加元素。    

4.使用 make() 函数构造切片

  语法:

    make( []T, size, cap )

      T:切片的元素类型

      size:就是为这个类型分配多少个元素

      cap:预分配的元素数量,这个值设定后不影响 size,只是能提前分配空间,降低多次分配空间造成的性能问题

package main

import "fmt"

func main() {

    a := make([]int, 2)
b := make([]int, 2, 10)
fmt.Println(a, b)
fmt.Println(len(a), len(b)) } //运行结果
//[0 0] [0 0]
//2 2

使用make函数创建切片

  1. a 和 b 均是预分配 2 个元素的切片,只是 b 的内部存储空间已经分配了 10 个,但实际使用了 2 个元素。

  2. 容量不会影响当前的元素个数,因此 a 和 b 取 len 都是 2。  

(ps:使用 make() 函数生成的切片一定发生了内存分配操作。但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。)

5、使用append向切片追加单个元素

  1.append() 可以为切片动态添加元素。

  2.每个切片会指向一片内存空间,这片空间能容纳一定数量的元素。

  3.当空间不能容纳足够多的元素时,切片就会进行“扩容”。

  4.“扩容”操作往往发生在 append() 函数调用时。

package main

import "fmt"

func main() {
//声明一个整型切片。
var numbers []int for i := 0; i < 10; i++ {
//循环向 numbers 切片添加10个数。
numbers = append(numbers, i)
//打印输出切片的长度、容量和指针变化。使用 len() 函数查看切片拥有的元素个数,使用 cap() 函数查看切片的容量情况
fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)
}
} //运行结果
//len: 1 cap: 1 pointer: 0xc00001c060
//len: 2 cap: 2 pointer: 0xc00001c090
//len: 3 cap: 4 pointer: 0xc000016120
//len: 4 cap: 4 pointer: 0xc000016120
//len: 5 cap: 8 pointer: 0xc00001e180
//len: 6 cap: 8 pointer: 0xc00001e180
//len: 7 cap: 8 pointer: 0xc00001e180
//len: 8 cap: 8 pointer: 0xc00001e180
//len: 9 cap: 16 pointer: 0xc000088000
//len: 10 cap: 16 pointer: 0xc000088000

append时,切片扩容分析

  a.len() 函数并不等于 cap。

  b.当元素个数超过cap()的数量时,切片会进行扩容

  c.扩容后切片的内存地址发生改变

  d.但是切片的名称没有发生改变。

6、使用append向切片中追加多个元素/其他切片

package main

import "fmt"

func main() {

    var car []string

    // 添加1个元素
car = append(car, "OldDriver") // 添加多个元素
car = append(car, "Ice", "Sniper", "Monk")
// 添加切片
team := []string{"Pig", "Flyingcake", "Chicken"}
car = append(car, team...)
fmt.Println(car) } //运行结果
//[OldDriver Ice Sniper Monk Pig Flyingcake Chicken]

append追加多个元素

  在team后面加上了...,表示将 team 整个添加到 car 的后面。

  

  

go语言之---数组(array)和切片(slice)的更多相关文章

  1. go 数组(array)、切片(slice)、map、结构体(struct)

    一 数组(array) go语言中的数组是固定长度的.使用前必须指定数组长度. go语言中数组是值类型.如果将数组赋值给另一个数组或者方法中参数使用都是复制一份,方法中使用可以使用指针传递地址. 声明 ...

  2. Go语言【第十二篇】:Go数据结构之:切片(Slice)、范围(Range)、集合(Map)

    Go语言切片(Slice) Go语言切片是对数组的抽象,Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片("动态数组"),与数 ...

  3. Go语言基础五:引用类型-切片和映射

    切片 Go的数组长度不可以改变,在某些特定的场景中就不太适用了.对于这种情况Go语言提供了一种由数组建立的.更加灵活方便且功能强大的包装(Wapper),也就是切片.与数组相比切片的长度不是固定的,可 ...

  4. go语言 类型:数组

    在go语言中数组array是一组特定长度的有序的元素集合. go的数组类型由两部分组成——类型和长度,二者缺一不可.数组本来就是一块存储相同类型元素的连续内存空间,因此决定一个数组的类型,必然需要决定 ...

  5. Go 数组(array) & 切片(slice)

    数组 数组是一组固定长度的序列 数组类型 数组的类型不仅和储存元素的类型有关,还和数组长度有关,不同长度的数组是不同的类型 不同类型的数组不能共用一个函数 func main() { var a [1 ...

  6. go语言学习-数组-切片-map

    数组 go语言中数组的特点: 数组的长度是固定的,并且长度也是数组类型的一部分 是值类型,在赋值或者作为参数传递时,会复制整个数组,而不是指针 定义数组的语法: var arr1 = [5]int{1 ...

  7. go语言的 数组、slice、map使用(转)

    golang群 点击加入 go语言的 数组.slice.map使用, 由于网上有很好的说明, 不需要再写了,请看这几篇: Go语言中的 Array, Slice和 Map 深入学习golang五篇,以 ...

  8. go递归函数如何传递数组切片slice

    数组切片slice这个东西看起来很美好,真正用起来会发现有诸多的不爽. 第一,数组.数组切片混淆不清,使用方式完全一样,有时候一些特性又完全不一样,搞不清原理很容易误使用. 第二,数组切片的appen ...

  9. Go语言学习笔记十一: 切片(slice)

    Go语言学习笔记十一: 切片(slice) 切片这个概念我是从python语言中学到的,当时感觉这个东西真的比较好用.不像java语言写起来就比较繁琐.不过我觉得未来java语法也会支持的. 定义切片 ...

随机推荐

  1. Java反射复习笔记

    目录 反射 获取反射的三种方式: Class对象的功能 获取 成员变量/成员变量们 获取 成员方法/成员方法们 获取构造方法们 获取全类名 Field:成员变量 Method:成员方法 Constru ...

  2. 我叫Mongo,收了「查询基础篇」,值得你拥有

    这是mongo第二篇「查询基础篇」,后续会连续更新6篇 mongodb的文章总结上会有一系列的文章,顺序是先学会怎么用,在学会怎么用好,戒急戒躁,循序渐进,跟着我一起来探索交流. 通过上一篇基础篇的介 ...

  3. Mybatis 批量更新遇到的小问题

    小问题 记一个开发过程中因为小细节的遗漏而引发的 "莫名其妙",公司中有个2B(to B)供应链项目,持久层用的是 JPA,这里我就不吐槽 JPA 了,这种 SQL 嵌入在代码里的 ...

  4. C++动态存储方式与静态存储方式

    如果从变量值存在的时间(即生存期)来分,可将程序中的变量分为:动态存储方式和静态存储方式.它们所占用的存储空间区域不同. C++存储空间区域 代码区:存放可执行程序的程序代码.静态存储区:存放静态变量 ...

  5. iOS开发 objective C 代码布局

    代码布局抛弃storyboard,用代码生成界面,它的优劣不谈 首先在项目设置中,更改应用的"入口" 不选main,清空它 然后在AppDelegate.m中,更改(添加内容),别 ...

  6. C++ 基础 1:C++ 对 C 语言的增强

    1 namespace 命名空间 1.1 C++ 命名空间的定义 C++标准 引入了关键字 namespace(命名空间),可以更好地控制标识符的作用域. namespace name { ... } ...

  7. xenserver中linux虚拟机修改启动顺序

    xenserver是思杰的一款类似于vmware ESXI的虚拟化平台,或者说虚拟化操作系统,上面可以安装许多虚拟机,但是当你装完linux虚拟机,你会发现一个问题,不能像windows vm那样直接 ...

  8. yum 常用命令使用

    1.向服务器上传文件或者下载文件 我们知道我们经常需要向服务器上传文件,或者从服务器下载文件,rz和sz命令可以满足我们的要求, 只不过默认情况下是不能使用的.我们需要使用yum install lr ...

  9. SQL Server DATEDIFF() 函数用法

    定义和用法 DATEDIFF() 函数返回两个日期之间的时间,例如计算年龄大小. DATEDIFF(datepart,startdate,enddate)startdate 和 enddate 参数是 ...

  10. uniapp开发小程序

    uniapp开发小程序 uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS.Android.Web(响应式).以及各种小程序(微信/支付宝/百度/头条 ...