Go语言学习笔记(三)数组 & 切片 & map

简介:

加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959

数组 Arrays

数组是同一种数据类型的固定长度的序列。

数组是值类型,因此改变副本的值,不会改变本身的值;

当作为方法的入参传入时将复制一份数组而不是引用同一指针。

通过从0开始的下标索引访问元素值。

数组定义

复制代码
var a []int
a = make([]int, 5)
var a1 [5]int = [5]int{1, 2, 3, 4, 5}      //len:5 content:[1 2 3 4 5]
var a2 = [5]int{1, 2, 3, 4, 5}             //len:5 content:[1 2 3 4 5]
var a3 = [...]int{1, 2, 3, 4, 5}           //len:5 content:[1 2 3 4 5]
var a4 = [...]int{1: 100, 2: 200}          //len:3 content:[0 100 200]
var a5 = [...]string{1: "nick", 2: "dawn"} //len:3 content:[ nick dawn]
复制代码

数组定义后,长度不能变。

长度是数组类型的一部分,具有不同长度的数组,其类型是不同的。

因此,var a[5] int 和 var a[9]int 是不同的类型。

数组使用

通过下标访问,超出会报错

arr := [5]int{1, 2, 3}
//fmt.Println(arr[5])    //报错

通过for遍历数组元素

复制代码
func main()  {
    arr := [5]int{1, 2, 3}
    for i:=0; i<len(arr); i++ {
        fmt.Println(arr[i])    //12300
    }
    for i,v := range arr{
        fmt.Printf("index[%d]:content[%v]\n", i, v)
    }
}
复制代码

值类型数组赋值,改变副本不会改变自身

复制代码
func main()  {
    arr := [5]int{1, 2, 3}
    arr2 := arr
    arr2[0] = 10
    fmt.Println(arr)    //[1 2 3 0 0]
    fmt.Println(arr2)    //[10 2 3 0 0]
}
复制代码
  栗子(斐波那契数列)

 

二维数组 

多维数组,二维数组举例

var a1 [2][5]int

二维数组遍历

复制代码
func main() {
    var a1 [2][5]int = [...][5]int{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}

    for row, v := range a1 {
        for col, v1 := range v {
            fmt.Printf("(%d,%d)=%d ", row, col, v1)
        }
        fmt.Println()
    }
}
复制代码

 

切片 Slices

切片是长度可变、容量固定的相同的元素序列。

切片是数组的一个引用,因此切片是引用类型。

因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。

slice 与 array 接近,但是在新的元素加入的时候可以增加长度。slice 总是指向底层的一个 array。slice本身不是数组,slice 是一个指向 array的指针。

切片定义 

创建切片跟创建数组唯一的区别在于 Type 前的“ [] ”中是否有数字,为空,则代表切片,否则则代表数组。

复制代码
s1 := [] int{1, 2, 3}          //直接初始化切片,[]表示是切片类型,初始化值依次是1,2,3.其cap=len=3
s2 := arr[:]                   //初始化切片s2,是数组arr的引用
s3 := arr[startIndex:endIndex] //将arr中从下标startIndex到endIndex-1下的元素创建为一个新的切片
s4 := arr[startIndex:]         //缺省endIndex时将表示一直到arr的最后一个元素
s5 := arr[:endIndex]           //缺省startIndex时将表示从arr的第一个元素开始
s6 := s1[startIndex:endIndex]  //通过切片s6初始化切片截取s1
s7 := make([]int, len, cap)    //通过内置函数make()初始化切片s,cap可以省略(省略时,值等同于len)
复制代码

len() 与 cap()

长度是指已经被赋过值的最大下标+1,可通过内置函数len()获得。

容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。

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

切片使用

遍历及修改

for i, v := range slice0 {
    slice0[i] = strings.ToUpper(v)
    fmt.Printf("index[%d]content[%s,%s]\n", i, v, slice0[i])
}

append 及 copy

append操作:slice可以在尾部追加元素,甚至还可以将一个slice追加到另一个slice的尾部,如果最终的长度没有超过原始的slice,那么append操作将返回原来的slice,否则将重新分配内存地址。

copy操作:copy操作返回复制的元素的个数,复制的数量是len(src)和len(dst)中最小的值。

复制代码
slice := []int{1, 2}
fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[2],content:[1 2]
slice = append(slice, 5, 6, 8, 9)
fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[6],content:[1 2 5 6 8 9]

slicecp := make([]int, len(slice))
fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[6],content:[1 2 5 6 8 9]
n := copy(slicecp, slice)
fmt.Printf("len[%d],content:%v, retN:%d\n", len(slice), slice, n) //len[6],content:[1 2 5 6 8 9], retN:6
slicecp[0] = 10
fmt.Printf("len[%d],content:%v\n", len(slice), slice)     //len[6],content:[1 2 5 6 8 9]
fmt.Printf("len[%d],content:%v\n", len(slicecp), slicecp) //len[6],content:[10 2 5 6 8 9]

sliceN := append(slice, slicecp...)
fmt.Printf("len[%d],content:%v\n", len(sliceN), sliceN)    //len[12],content:[1 2 5 6 8 9 10 2 5 6 8 9]
复制代码

值类型修改值会影响本身。

slice0 := []string{"a", "b", "c", "d", "e"}
slice1 := slice0
slice1[0] = "Nick"
fmt.Println(slice0)    //[Nick b c d e]
fmt.Println(slice1)    //[Nick b c d e]

 

内存布局与扩容

切片是引用类型,指针内部只向一个数组。

 代码实现,内存地址表示是同一块地址。

复制代码
func main() {
    var a []int = []int{1, 2, 3, 4, 5}
    s := a[1:]
    fmt.Printf("a=%p, s=%p \n", &(a[1]), s) //a=0xc420016188, s=0xc420016188
    s = append(s, 10, 10, 10)
    fmt.Printf("a=%p, s=%p \n", &a[1], s)   //a=0xc420016188, s=0xc4200141c0
}
复制代码

切片的长度是可变的,那自动扩容是怎样的机制呢?

是 double(双倍),看下面代码。

复制代码
func main() {
    var a [5]int = [...]int{1, 2, 3, 4, 5}
    s := a[1:]
    fmt.Println(cap(s), len(s)) //4 4
    s = append(s, 10, 10, 10)
    fmt.Println(cap(s), len(s)) //8 7
    s = append(s, 10)
    fmt.Println(cap(s), len(s)) //8 8
    s = append(s, 10)
    fmt.Println(cap(s), len(s)) //16 9
    s = append(s, 10, 10, 10, 10)
    fmt.Println(cap(s), len(s)) //16 13
    s = append(s, 10, 10, 10, 10, 10, 10)
    fmt.Println(cap(s), len(s)) //32 19
}
复制代码
  模仿切片

 

map

map在Go语言中是作为一种内建类型存在。

key-value的数据结构,又叫字典或关联数组。

map是引用类型。

map声明是不会分配内存的,需要make初始化。

map声明初始化

声明

var a map[keytype]valuetype
var a map[string]string
var a map[string]int
var a map[int]string
var a map[string]map[string]string  //嵌套

 声明并初始化

复制代码
var a map[string]string
a = make(map[string]string, 10)

a := make(map[string]string, 10)
a := make(map[string]string)

var a map[string]string = map[string]string{}
var a map[string]string = map[string]string{
    "A": "A",  //注意是逗号
}
复制代码

 

map 使用

增删改查

m["name"] = "Nick"   // "create"
delete(m, "name")    // "delete"
m["name"] = "Dawn"   // "update"
name := m["name"]    // "read"

读取不异常

name, errbool := m["name"]
if !errbool {
    m["name"] = "Nick"
}

二维map

复制代码
func modify(a map[string]map[string]string) {
    _, ok := a["name"]
    if !ok {
        a["name"] = make(map[string]string)
    }
    a["name"]["Nick"] = "suoning"
    a["name"]["Nicky"] = "manyRou"
}

func testMap3() {
    var a map[string]map[string]string
    a = make(map[string]map[string]string, 10)    //初始化一维
    a["name"] = make(map[string]string)           //初始化二维

    modify(a)
    fmt.Println(a)
}
复制代码

 

slice of map

Items := make([]map[int][int], 5)
For i := 0; i < 5; i++ {
        items[i] = make(map[int][int])
}

 

map 排序

  1. 先获取所有key,把key进行排序
  2.  按照排序好的key,进行遍历
复制代码
import "sort"

func testMapSort() {
    var a map[int]int
    a = make(map[int]int, 5)

    a[8] = 10
    a[5] = 10
    a[2] = 10
    a[1] = 10
    a[9] = 10

    var keys []int
    for k, _ := range a {
        keys = append(keys, k)
    }

    sort.Ints(keys)

    for _, v := range keys {
        fmt.Println(v, a[v])
    }
}
复制代码

 

map 反转

初始化另外一个map,把key、value互换即可

复制代码
func testMapSort1() {
    var a map[string]int
    var b map[int]string

    a = make(map[string]int, 5)
    b = make(map[int]string, 5)

    a["name"] = 53
    a["ege"] = 10

    for k, v := range a {
        b[v] = k
    }

    fmt.Println(b)
}

 

复制代码
目录
相关文章
|
Go
Go 语言学习之map
Go 语言学习之map
105 0
|
Go
go语言基础数据结构学习 ---- 字典(map)
go语言基础数据结构学习 ---- 字典(map)
234 0
|
Go
Go——小白学习之map
map的使用,key值唯一,打印出是无序的,注意坐标(key)与数组坐标不一样 定义: m3 := map[int]string{1: "mile", 2: "go"} m3[1] = "litter" m3[3] = "gogogo"    //超出范围,错误 fmt.
1017 0
|
7月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
7月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
1月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
1月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
2月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
2月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
205 0
|
3月前
|
开发框架 JSON 中间件
Go语言Web开发框架实践:路由、中间件、参数校验
Gin框架以其极简风格、强大路由管理、灵活中间件机制及参数绑定校验系统著称。本文详解其核心功能:1) 路由管理,支持分组与路径参数;2) 中间件机制,实现全局与局部控制;3) 参数绑定,涵盖多种来源;4) 结构体绑定与字段校验,确保数据合法性;5) 自定义校验器扩展功能;6) 统一错误处理提升用户体验。Gin以清晰模块化、流程可控及自动化校验等优势,成为开发者的优选工具。