(五)Go-----数组(映射map),切片,堆栈,队列,多维切片,模块,字符串/字节切片(函数)

一. 数组

  1. 数组长度不可变
  2. 所有元素类型相同
  3. 重复赋值,只能是长度相同的数组
  4. 元素,为非负证书的常量
  5. 声明var,需正数定:类型,长度
  6. %q 默认会有双引号,会显示其数值类型
  7. %v调用函数自己的格式

在这里插入图片描述

1. 声明,获取

var nums [10]int

// 不声明长度,有多少元素,长度就为多少
var nums [...]int{12345}


//通过索引赋值
nums :=[10]int{1:2,8:10}

在这里插入图片描述

简易声明

nums :=[3]int{1,2,3}

2. 判断,遍历

相等 A == B
长度 len(A)
索引 nums[0] , nums[10]=20,

遍历数组
在这里插入图片描述
for range 遍历,不需要索引获取

nums :=[10]int{0,1,2,3,4,5,6,7,8,9}
	//索引 index , 字符value
	for index,value := range nums{
		fmt.Println(index,"\t:",value)
	}
	//index可以变为_
	for _,value := range nums{
		fmt.Println(value)
	}

在这里插入图片描述

3. 切片

切片生成的类型为 [ ]int,并不是数组,第三位为切片的容量
长度,不能大于数组的容量 左包含,又不包含
容量
在这里插入图片描述

3. 多维数组

不能求长度
声明

var nums [3][2]int

赋值

nums[0]=[2]int{1,2}

//索引声明
nums[0][0]=10

遍历
for range
在这里插入图片描述

4. (符合数组map)映射 ,字典

map 也叫做符合数组hash表字典一堆 未 排序的键值对集合

  1. 是一个无序的key/value存储
  2. key只能使用运算符的数值类型(字符串,数字,布尔,数组)
  3. value为任意类型,slice,map等
  4. 可以使用 ==!= 来进行判等操作,换句话说就是key必须是可哈希的。(你的 key 不能是切片,不能是字典,不能是函数)
  5. 未初始化的 score 的零值为nil,无法直接进行赋值要使用 make 函数先对其初始化)–也就是初始化定义如果没有直接赋值,需要用make进行声明,才能够赋值
map声明语法
        var 变量名  map[keytype]valuetype

map类型的变量默认初始值为nil,需要使用make()函数来分配内存。语法为

make(map[KeyType]ValueType, [cap])

var sources map[string]int

	//字面量
	sources =map[string]int{"老大":30,"老二":28,"老三":25}
	fmt.Println(sources)
	sources=make(map[string]int)

或者
	m1 := map[string]string{
        "坦克": "德玛西亚",
        "射手": "伊泽瑞尔",
        "辅助": "日女",
    }


长度len(source)

					key
fmt.Println(sources["老二"])
v,ok :=sources["老二"]


map查找值
//v值,ok判断是否存在
    val, ok := m1["k4"]
    if ok {
        fmt.Printf("k4的值是:%v\n", val)
    }

在这里插入图片描述
初始化,通过ok去判断—为true执行子语句
在这里插入图片描述

如果 key 不存在,也不报错,会返回其value-type 的零值


修改value

sources["老大"]=40

如果修改key,需要删除,然后添加
:如果key不存在就是添加(随意插入),如果不存在(静默处理)

sources["猪八戒"]=1000

delete(sources,"老三")

遍历—无序的

for k,v :=range sources{
	fmt.Println(k,v)	
} 

判断 key 是否存在

当key不存在,会返回value-type的零值 ,所以你不能通过返回的结果是否是零值来判断对应的 key 是否存在,因为 key 对应的 value 值可能恰好就是零值。

其实字典的下标读取可以返回两个值,使用第二个返回值都表示对应的 key 是否存在,若存在ok为true,若不存在,则ok为false

func main() {
    scores := map[string]int{"english": 80, "chinese": 85}
    math, ok := scores["math"]
    if ok {
        fmt.Printf("math 的值是: %d", math)
    } else {
        fmt.Println("math 不存在")
    }
}

我们将上面的代码再优化一下

import "fmt"

func main() {
    scores := map[string]int{"english": 80, "chinese": 85}
    if math, ok := scores["math"]; ok {
        fmt.Printf("math 的值是: %d", math)
    } else {
        fmt.Println("math 不存在")
    }
}

如何对字典进行循环

Go 语言中没有提供类似 Python 的 keys() 和 values() 这样方便的函数,想要获取,你得自己循环。
循环还分三种

1. 获取 key 和 value

import "fmt"

func main() {
    scores := map[string]int{"english": 80, "chinese": 85}

    for subject, score := range scores {
        fmt.Printf("key: %s, value: %d\n", subject, score)
    }
}

2. 只获取key,这里注意不用占用符。

import "fmt"

func main() {
    scores := map[string]int{"english": 80, "chinese": 85}

    for subject := range scores {
        fmt.Printf("key: %s\n", subject)
    }
}

3. 只获取 value,用一个占位符替代。

import "fmt"

func main() {
    scores := map[string]int{"english": 80, "chinese": 85}

    for _, score := range scores {
        fmt.Printf("value: %d\n", score)
    }
}

多元的

定义一个映射,在他的基础上也映射
相当于他的value也是一个映射

							#注意这里的value类型为string,也就是说必须带双引号
var user map[string]map[string]string

user =map[string]map[string]string{"李明":{"中国":"陕西","年纪":"大二","成绩":"99","练习方式":"123412421"}}
fmt.Printf("%T\n,%#v\n",user,user)

在这里插入图片描述

赋值,相当于多元数组一样

users["李明"]["成绩"]=100

排序

相当于对索引排序

	m := map[string]string{"q": "q", "w": "w", "e": "e", "r": "r", "t": "t", "y": "y"}
    fmt.Println(m)
    //定义一个 string类型切片
    var slice []string
    //循环遍历map,取出所有的key和value
    for k, _ := range m {
        //循环将key添加到切片中
        slice = append(slice, k)
    }
    fmt.Printf("切片slice值 : %v\n", slice)
    //调用排序包,对切片进行排序,按照字母顺序排序
    sort.Strings(slice[:])
    fmt.Printf("排序后 切片slice值 : %v\n", slice)
    for _, v := range slice {
        fmt.Printf("排序后 m[%v]=%v\n", v, m[v])
    }

投票选举问题

在这里插入图片描述
优化:没有直接加一
在这里插入图片描述
获取每个字符出现的次数

遍历字符串key结果为麻点rune类型
所以value为int类型

在这里插入图片描述

二. 切片 Slice

切片是可动态变化的序列,是对数组的引用,引用类型,遵循引用传递的机制

用的是数组进行存储

  1. 一个长度可变的数组,存储地址在内存中
  2. 只能存储类型相同的元素
  3. slice由三个部分构成,指针、长度、容量
  4. 类型为 []int
    指针:指向切片第一个元素指向数组的地址
    长度:切片元素的数量
    容量:切片开始到结束位置的数量
  5. 切片也可以进行切片(获取新的切片
  6. 左包含,右不包含

缺点

声明 : :不需要指定长度的数组

var name []string
var num  []int

数组切片赋值
在这里插入图片描述

获取长度len()
获取容量cap()

  1. 未定义的时候长度,容量相等
fmt.Printf("slice第一个元素地址%p\n",&s1[0])
fmt.Printf("对应数组元素的地址%p\n",&months[4])

切片的创建方式make

定义切片,然后引用已经创建好的数组,数组可见
内置make函数创建切片,底层数组看不见,只能通过slice访问元素
make创建切片内存分配图

cap取到最后一位多了不要
在这里插入图片描述
在这里插入图片描述
要检查切片是否为空,使用len(s) == 0来判断

new()和make()的区别

看起来二者没有什么区别,都在堆上分配内存,但是它们的行为不同,适用于不同的类型。

new(T) 为每个新的类型T分配一片内存,初始化为 0 并且返回类型为*T的内存地址:这种方法 返回一个指向类型为 T,值为 0 的地址的指针,它适用于值类型如数组和结构体;它相当于 &T{}。

make(T) 返回一个类型为 T 的初始值,它只适用于3种内建的引用类型:切片、map 和 channel

1. 定义切片的容量(make)

make函数:指定长度,容量
len指定长度,打印几个元素

内置make函数,make(类型,len,cap),注意cap>=len,容量可以省略,默认等于长度

			类型  len
nums =make([]int,3)
					容量为5
nums =make([]int,3,5)

在这里插入图片描述
切片直接对应数组,如同make方式

	var s1 []int = []int{1, 2, 3, 4, 5}
    fmt.Println(s1)
    fmt.Println(len(s1))
    fmt.Println(cap(s1))

遍历切片

    var arr [5]int = [...]int{11, 22, 33, 44, 55}
    s1 := arr[1:4]
    //for循环遍历
    for i := 0; i < len(s1); i++ {
        fmt.Printf("s1[%v]=%v\n", i, s1[i])
    }
    fmt.Println()
    //for range方式遍历切片
    for i, v := range s1 {
        fmt.Printf("索引i=%v 值v=%v\n", i, v)
    }

2 . 切片(增,删,改,查)

左包含,右不包

  1. len()
  2. Cap 统计切片容量,最大存放多少元素
//创建切片
    var slice1 []int = []int{100, 200, 300}
    fmt.Printf("slice1容量=%v 长度=%v\n", cap(slice1), len(slice1))
  1. append
  2. copy

–用索引

fmt.Println(nums[0])

修改

nums[0]=10

追加::添加一个元素,增加的是长度,容量不变
如果超出长度,长度增加,容量会成倍增加
需要返回值更新

  1. append原理就是对底层数组扩容,go会创建新的数组,将原本元素拷贝到新的数组中
    切片numSlice的容量按照1,2,4,8,16这样的规则自动进行扩容,每次扩容后都是扩容前的2倍

// 追加一个切片, … 表示解包,不能省略

myarr = append(myarr, []int{7, 8})

// 在第一个位置插入元素

myarr = append([]int{0}, myarr)

// 在中间插入一个切片(两个元素)

myarr = append(myarr[:5], append([]int{5,6}, myarr[5:]))

如果是要将一个切片追加到另一个切片尾部,需要使用 ... 语法将第2个参数展开为参数列表

a := []string{"John", "Paul"}
b := []string{"George", "Ringo", "Pete"}
a = append(a, b...) // equivalent to "append(a, b[0], b[1], b[2])"
// a == []string{"John", "Paul", "George", "Ringo", "Pete"}

个参数展开为参数列表。
2. slice重新引用新的数组
3. 这个数组不可见

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

在这里插入图片描述

复制:copy(目的,源)
不会改变现有大小

A :=[]int{9.8.7}
B :=[]int{1,2,3,4,5}
copy(B,A)
//结果B ={9.8.7.4.5}

copy :函数 copy 在两个 slice 间复制数据,复制长度以 len 小的为准。两个 slice 可指向同一底层数组,允许元素区间重叠。

package main

import (
    "fmt"
)

func main() {

    data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    fmt.Println("array data : ", data)
    s1 := data[8:]
    s2 := data[:5]
    fmt.Printf("slice s1 : %v\n", s1)
    fmt.Printf("slice s2 : %v\n", s2)
    copy(s2, s1)
    fmt.Printf("copied slice s1 : %v\n", s1)
    fmt.Printf("copied slice s2 : %v\n", s2)
    fmt.Println("last array data : ", data)

}

输出结果:

array data :  [0 1 2 3 4 5 6 7 8 9]
slice s1 : [8 9]
slice s2 : [0 1 2 3 4]
copied slice s1 : [8 9]
copied slice s2 : [8 9 2 3 4]
last array data :  [8 9 2 3 4 5 6 7 8 9]

删除
删除第一个

nums[1:]

删除最后一个

nums[:len(nums)-1]

删除中间的:相当于将后面的前移,然后缩小(中间几个元素)

//删除2:5
copy(num[2:],num[5:])
num[:len(num)-3]
func main() {
	// 从切片中删除元素
	a := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// 要删除索引为2的元素
	a = append(a[:2], a[3:]...)
	fmt.Println(a) //[30 31 33 34 35 36 37]
}

调整大小:resize

package main

import (
    "fmt"
)

func main() {
    var a = []int{1, 3, 4, 5}
    fmt.Printf("slice a : %v , len(a) : %v\n", a, len(a))
    b := a[1:2]
    fmt.Printf("slice b : %v , len(b) : %v\n", b, len(b))
    c := b[0:3]
    fmt.Printf("slice c : %v , len(c) : %v\n", c, len(c))
}
输出结果:

    slice a : [1 3 4 5] , len(a) : 4
    slice b : [3] , len(b) : 1
    slice c : [3 4 5] , len(c) : 3

思考题

  1. 超出原 slice.cap 限制,就会重新分配底层数组,即便原数组并未填满。
package main

import (
    "fmt"
)

func main() {

    data := [...]int{0, 1, 2, 3, 4, 10: 0}
    s := data[:2:3]

    s = append(s, 100, 200) // 一次 append 两个值,超出 s.cap 限制。

    fmt.Println(s, data)         // 重新分配底层数组,与原数组无关。
    fmt.Println(&s[0], &data[0]) // 比对底层数组起始指针。

}
输出结果:

    [0 1 100 200] [0 1 2 3 4 0 0 0 0 0 0]
    0xc4200160f0 0xc420070060
  1. 为什么
package main

import (
    "fmt"
)

func main() {
    var numbers4 = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    myslice := numbers4[4:6:8]
    fmt.Printf("myslice为 %d, 其长度为: %d\n", myslice, len(myslice))

    myslice = myslice[:cap(myslice)]
    fmt.Printf("myslice的第四个元素为: %d", myslice[3])
}

结果

myslice为 [5 6], 其长度为: 2
myslice的第四个元素为: 8

结论:

在这里插入图片描述
在这里插入图片描述

三. 队列(先进先出)

添加元素:追加方式
删除元素:队头
在这里插入图片描述

添加元素

queue :=[]int
queue =append(queue,1)
queue =append(queue,2)
queue =append(queue,3)

删除元素

queue = queue[1:]

在这里插入图片描述

四. 堆栈(先进后出)

stack
在这里插入图片描述
移除元素,从对尾移除

num = num[:len(num)-1]

五. 多维切片

	points :=[][]int{}
	// [][]int 类型,0长度
	num :=make([][]int,0)
	points=append(points,[]int{1,2,3})
	points=append(points,[]int{4,5,6})
	fmt.Println(points)

访问

point[0][0]

六. 模块

地址https://golang.google.cn/pkg/

例如:
sort 排序模块 Ints() , Strings()
在这里插入图片描述

七 . 字符串/ 字节切片

string底层就是byte数组,因此string同样可以进行切片处理

1. 字符串 常用函数

区别
bytes·:将buffer对象转化为字节切片 string`:将buffer对象转换为字符串

转换可以将string通过bute[] 转换为字节切片,同时也可以转换为string

常用包
string包中用UTF-8

  1. 在本地查看文档cmd—godoc --help,访问本地localhost:6060
  2. 也可以用go doc strings查看go doc string.Fields
    官方文档
Compare   	比较字符串   错误-1
Contains    是否包含子字符串
Count  		子字符串出现的次数
EqualFold  	不区分大小写比较
Fields  	按空白字符分割字符串(\n,空格,\t,\r,\f,\v)
HasPrefix  	是否以字符串 开头
HasSuffix  	是否以字符串  结尾
Index 		获取字符串首次出现的次数

Split  		分割字符串为切片,以某个字符串为分隔符

Join  		将字符串切片连接strings.Join([]string{"abc","def"},":")
LastIndex  	获取子字符串最后一次出现的位置
Repeat   	把字符串重复几次
Replace		把字符串替换 
ToLower		把字符串转换为小写
ToUpper		把字符串转换为大写
ToTitle		把字符串转换为大写

package main
import (
	"fmt"
	"strings"
)
func main() {
	//比较
	fmt.Println(strings.Compare("abc", "cbd"))
	//包含
	fmt.Println(strings.Contains("abcd", "cd"))
	//子字符串出现的次数
	fmt.Println(strings.Count("abcdabababab", "ab"))
	fmt.Println(strings.EqualFold("ABCD","abcd"))
	fmt.Println(strings.Fields("ab cd\nef\rgh\flm"))
	fmt.Println(strings.HasPrefix("abcd","a"))
	fmt.Println(strings.HasSuffix("abcd","d"))
	fmt.Println(strings.Index("abcadaeafg","f"))
	fmt.Println(strings.Split("abcdefg"	,"e"))
	fmt.Println(strings.Join([]string{"abc","def"},":"))
	fmt.Println(strings.LastIndex("abcdabababab","ab"))
	//重复几次
	fmt.Println(strings.Repeat("abc",3))
	//替换ab为gg,替换3次
	fmt.Println(strings.Replace("abcdefgabacdab","ab","gg",3))
}

2. 字节 常用函数

定义字节切片

var bytes []byte= []byte{'a','b','c'}

字节 转换 为字符串

s :=string(bytes)
fmt.Printf("%T,%v\n",s,s)

将字符串转换为字节

by := []bytes(s)
fmt.Printf("%T,%v\n",s,s)

在这里插入图片描述
函数
类似于string

在这里插入图片描述
计算长度:用utf8
中文,一个占三个字节,但用utf8就为一个字符
在这里插入图片描述
精确计算 字符串,计算utf8 字符长度
如果是汉字字符串(一个汉字等于三个字节)
要计算正确的长度utf8

s :="我爱洗澡"
m :=utf8.RuneCountInString(s)
//结果为  4
fmt.Println(m)

八. 字符串转换( String包 )

strconv

1. 字符串到其他类型

用的是Prese
在这里插入图片描述

  1. bool
    stconv.ParsBool()
//v值,err判断是否为nil
	if v,err := strconv.ParseBool("true");err==nil{
		fmt.Println(v)
	}
  1. int类型
    Atoi直接转化为int
if v,err :=strconv.Atoi("1234");err==nil{
		fmt.Println(v)
	}

PresInt需要指定多少进制的,转换为多少字节

	//把64,为16进制,转换为64字节
	//16*6+4=100
	if v,err :=strconv.ParseInt("64",16,64);err==nil{
		fmt.Println(v)
	}else {
		fmt.Println(err)
	}
  1. float类型
	if v,err :=strconv.ParseFloat("1.1111",64);err==nil{
		fmt.Println(v)
	}

2. 其他类型到字符串

在这里插入图片描述

fmt
Sprint将你的变量转换为字符串

在这里插入图片描述

3. 如何修改字符串

  1. 强制将string转化为[]byte,修改后转为string
    []byte只能处理英文和数字,不能处理汉字,汉字3个字节,会出现乱码
	arr1 := []byte(str1) //类型强转
    arr1[0] = 'g'
    str1 = string(arr1)
    fmt.Printf("str1=%v\n", str1)
  1. 将string转为[]rune指针类型,按字符处理,兼容汉字
arr2 := []rune(str1)
arr2[0] = '糕'
str1 = string(arr2)
fmt.Printf("str1=%v\n", str1)

例如:

package main
import (
    "fmt"
    "strings"
)
func main() {
    str := "hello world"
    //判断是不是以某个字符串开头,返回布尔值
    res0 := strings.HasPrefix(str, "http://")
    res1 := strings.HasPrefix(str, "hello")
    fmt.Printf("res0 is %v\n", res0)
    fmt.Printf("res1 is %v\n", res1)
    //判断是不是以某个字符串结尾
    res3 := strings.HasSuffix(str, "http://")
    res4 := strings.HasSuffix(str, "world")
    fmt.Printf("res3 is %v\n", res3)
    fmt.Printf("res4 is %v\n", res4)
    //判断字符在字符串中首次出现的索引位置,没有返回-1
    res5 := strings.Index(str, "o")
    res6 := strings.Index(str, "x")
    fmt.Printf("res5 is %v\n", res5)
    fmt.Printf("res6 is %v\n", res6)
    //返回字符最后一次出现的索引位置,没有返回-1
    res7 := strings.LastIndex(str, "o")
    res8 := strings.LastIndex(str, "x")
    fmt.Printf("res7 is %v\n", res7)
    fmt.Printf("res8 is %v\n", res8)
    //字符串替换
    res9 := strings.Replace(str, "world", "golang", 2)
    res10 := strings.Replace(str, "world", "golang", 1)
    //trings.Replace("原字符串", "被替换的内容", "替换的内容", 替换次数)
    //原字符串中有2个world,才能替换2次
    fmt.Printf("res9 is %v\n", res9)
    fmt.Printf("res10 is %v\n", res10)
    //求字符在字符串中出现的次数,不存在返回0次
    countTime0 := strings.Count(str, "h")
    countTime1 := strings.Count(str, "x")
    fmt.Printf("countTime0 is %v\n", countTime0)
    fmt.Printf("countTime1 is %v\n", countTime1)
    //重复几次字符串
    res11 := strings.Repeat(str, 0)
    res12 := strings.Repeat(str, 1)
    res13 := strings.Repeat(str, 2)
    // strings.Repeat("原字符串", 重复次数)
    fmt.Printf("res11 is %v\n", res11)
    fmt.Printf("res12 is %v\n", res12)
    fmt.Printf("res13 is %v\n", res13)
    //字符串改大写
    res14 := strings.ToUpper(str)
    fmt.Printf("res14 is %v\n", res14)
    //字符串改小写
    res15 := strings.ToLower(str)
    fmt.Printf("res15 is %v\n", res15)
    //去除首尾的空格
    res16 := strings.TrimSpace(str)
    fmt.Printf("res16 is %v\n", res16)
    //去除首尾指定的字符,遍历l、d、e然后去除
    res17 := strings.Trim(str, "ld")
    fmt.Printf("res17 is %v\n", res17)
    //去除开头指定的字符
    res18 := strings.TrimLeft(str, "he")
    fmt.Printf("res18 is %v\n", res18)
    //去除结尾指定的字符,遍历d、l、r
    res19 := strings.TrimRight(str, "dlr")
    fmt.Printf("res19 is %v\n", res19)
    //用指定的字符串将string类型的切片元素结合
    str1 := []string{"hello", "world", "hello", "golang"}
    res20 := strings.Join(str1, "+")
    fmt.Printf("res20 is %v\n", res20)
}

注意

切片:传递的是地址,修改A,B也会改变

数组:是值传递,修改B,A地址中的内容不变

  • Go 中数组赋值函数传参都是值复制的。

  • 切片传数组参数,既可以达到节约内存的目的,也可以达到合理处理好共享内存的问题。

  • 切片是引用传递,所以它们不需要使用额外的内存并且比使用数组更有效率

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值