go 集合数据结构
数组
package main
import (
"fmt"
)
func main(){
//数组
var s1 [3]string=[3]string{"t","你好","小杜"}//数组初始化
var s2 [4]string
s2[0]="你好"
s1[0]="m"
for i,v:=range s2{
fmt.Println(i,v)
}
//数组初始化
var R1 = [...]string{"wc","你好","小鹿"}
for _,v:=range R1{
fmt.Println(v)
}
R2:= [...]string{"wc","你好","小鹿"}
for _,v:=range R2{
fmt.Println(v)
}
R3:= [3]string{2:"小熊"}
for _,v:=range R3{
fmt.Println(v)
}
}
执行结果
PS D:\golang\goproject\src\lnhgo> go run day02\demo01\main.go
0 你好
1
2
3
wc
你好
小鹿
wc
你好
小鹿
小熊
数组比较
package main
import (
"fmt"
)
func main(){
//数组初始化
var R1 = [...]string{"wc","你好","小鹿"}
for _,v:=range R1{
fmt.Println(v)
}
R2:= [...]string{"wc","你好","小鹿"}
for _,v:=range R2{
fmt.Println(v)
}
if R1==R2{
fmt.Println("exit")
}
}
执行结果
wc
你好
小鹿
wc
你好
小鹿
exit
多维数组
package main
import (
"fmt"
)
func main(){
//初始化
var str [3][4]string= [3][4]string{{"go","1h","bobby","go体系课程"},{"python","2h","橘子","python体系课程"},{"grpc","2H","小鹿","grpc"}}
//遍历
for _,v:=range str{
for _,a:=range v{
fmt.Println(a)
}
}
}
切片介绍
这是 Go 切片最重要的知识点之一:切片赋值不会复制数据,只会复制切片描述符(header)。
你的代码:
s2 = s1
s3 = s1[:]
s5 := s1
这三种写法都没有复制底层数组。
切片内部结构
切片本质上只有三个字段:
type slice struct {
ptr *T
len int
cap int
}
例如:
s1 := []string{"go","mysql","es"}
内存大概是:
s1
┌─────────┐
│ ptr ────┼─────┐
│ len=3 │ │
│ cap=3 │ │
└─────────┘ │
▼
┌────────┬────────┬────────┐
│ go │ mysql │ es │
└────────┴────────┴────────┘
s2 = s1
s2 = s1
只是把 header 复制一份:
s1.ptr ─┐
▼
底层数组
s2.ptr ─┘
两个切片指向同一个数组。
所以:
s1[0] = "python"
实际上改的是:
底层数组[0] = "python"
因此:
fmt.Println(s2)
也会看到:
[python mysql es]
s3 = s1[:]
很多人以为这是复制。
其实不是。
s3 = s1[:]
只是重新切片:
s3 = s1[0:len(s1)]
仍然指向同一个数组。
s1.ptr ─┐
▼
底层数组
s3.ptr ─┘
因此也会受影响。
s5 := s1
和
s2 = s1
完全一样。
只是短变量声明。
copy()
你这里:
var s4 []string = make([]string, 3)
copy(s4, s1)
第一步:
make([]string,3)
创建了新的底层数组:
s4
│
▼
┌────┬────┬────┐
│ │ │ │
└────┴────┴────┘
然后:
copy(s4,s1)
把元素逐个复制过去:
s1 s4
┌────┬───────┬────┐ ┌────┬───────┬────┐
│ go │ mysql │ es │ ──► │ go │ mysql │ es │
└────┴───────┴────┘ └────┴───────┴────┘
此时两个数组已经独立。
所以:
s1[0] = "python"
变成:
s1:
[python mysql es]
s4:
[go mysql es]
怎么验证是不是同一个底层数组
打印地址:
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", s2)
fmt.Printf("%p\n", s3)
fmt.Printf("%p\n", s4)
fmt.Printf("%p\n", s5)
你会看到类似:
0xc0000100c0
0xc0000100c0
0xc0000100c0
0xc000012120
0xc0000100c0
说明:
s1 s2 s3 s5
│
▼
同一个底层数组
s4
│
▼
独立底层数组
记住一句话:
切片赋值(=)复制的是切片头,不复制数据;copy() 才会复制底层数据。
这也是为什么 Go 面试里经常问:
a := []int{1,2,3}
b := a
b[0] = 100
fmt.Println(a)
答案是:
[100 2 3]
因为 a 和 b 指向同一个底层数组。
package main
import(
"fmt"
)
func main(){
var c []string
c=append(c, "t")
fmt.Printf("%T\n" ,c)
//切片初始化:1从数组直接创建2.使用make,3直接声明{}
var a1=[4]string{"小狗","小鸡","小鸭","小鹿"}
//使用make创建
var b1 = make([]string,5)
copy(b1,a1[0:2])//左闭右开
C1:=a1[0:1]
fmt.Printf("%T\n",C1)
var b2 []string
//b2[0]="t"会报错因为没有初始化空间
b2 = append(b2, "R")//调用函数不会报错
var b3 []string=make([]string, 6)
copy(b3,a1[:])
fmt.Println(b3[:3])//左闭右开
//合并两个切片
s1:=[]string{"go","grpc"}
s2:=[]string{"mysql","es"}
s1=append(s1, s2...)
s3:=[]string{"kafka","nginx","apache"}
s1= append(s1, s3[1:]...)
fmt.Println(s1)
//删除中间某个元素
s1=append(s1[:2],s1[3:]...)
fmt.Println(s1)
//删除开头某个元素
s1=s1[1:]
fmt.Println(s1)
//删除结尾元素
s1=s1[:len(s1)-1]
fmt.Println(s1)
//复制切片
s2=s1//拷贝底层数组地址值
s3=s1[:]//拷贝底层数组地址值
var s4 []string = make([]string, 3)//拷贝要有空间
copy(s4,s1)//拷贝底层数组的元素值
s5:=s1//拷贝底层数组地址值
fmt.Println(s1)
fmt.Println(s2)
fmt.Println(s3)
fmt.Println(s4)
fmt.Println(s5)
fmt.Println("===============================")
s1[0]="python"
fmt.Println(s1)
fmt.Println(s2)
fmt.Println(s3)
fmt.Println(s4)
fmt.Println(s5)
fmt.Println("+++++++++++++++++++++++++++++++++++++")
fmt.Printf("s1地址值=%p\n",&s1)
fmt.Printf("s2地址值=%p\n",&s2)
fmt.Printf("s3地址值=%p\n",&s3)
fmt.Printf("s4地址值=%p\n",&s4)
fmt.Printf("s5地址值=%p\n",&s5)
fmt.Println("+++++++++++++++++++++++++++++++++++++")
fmt.Printf("s1存储的底层数组地址值=%p\n",s1)
fmt.Printf("s2存储的底层数组地址值=%p\n",s2)
fmt.Printf("s3存储的底层数组地址值=%p\n",s3)
fmt.Printf("s4存储的底层数组地址值=%p\n",s4)
fmt.Printf("s5存储的底层数组地址值=%p\n",s5)
//fmt.Printf("s6地址址值=%p\n",&s1)
}
执行结果
[]string
[]string
[小狗 小鸡 小鸭]
[go grpc mysql es nginx apache]
[go grpc es nginx apache]
[grpc es nginx apache]
[grpc es nginx]
[grpc es nginx]
[grpc es nginx]
[grpc es nginx]
[grpc es nginx]
[grpc es nginx]
===============================
[python es nginx]
[python es nginx]
[python es nginx]
[grpc es nginx]
[python es nginx]
+++++++++++++++++++++++++++++++++++++
s1地址值=0xc000094078
s2地址值=0xc000094090
s3地址值=0xc0000940a8
s4地址值=0xc000094120
s5地址值=0xc000094138
+++++++++++++++++++++++++++++++++++++
s1存储的地址值=0xc0000b6010
s2存储的地址值=0xc0000b6010
s3存储的地址值=0xc0000b6010
s4存储的地址值=0xc0000880f0
s5存储的地址值=0xc0000b6010
说明go
package main
import (
"fmt"
)
func main(){
data:=[]int{1,2,3,4,5,6,7,8,9,10}
s1:=data[1:6]
s2:=data[2:7]
s2=append(s2, 1,2,8,89,14,17,18)//超出容量会拷贝扩容
s2[0]=71//这时候改的是新独立出来的底层数组元素地址;所以跟s1不一样
fmt.Println("s1=",s1)
fmt.Println("s2=",s2)
//s2=append(s2, 9,10,11,23,22,35,78,79,90,81,67,43,32,45,43,57,75,98,67,43,15,16,18,16,87,23,76,48,35,24,88,77)
// fmt.Println("s1=",s1)
// fmt.Println("s2=",s2)
}
结果
s1= [2 3 4 5 6]
s2= [71 4 5 6 7 1 2 8 89 14 17 18]
对比
package main
import (
"fmt"
)
func main(){
data:=[]int{1,2,3,4,5,6,7,8,9,10}
s1:=data[1:6]//从2开始
s2:=data[2:7]//从3开始
//s2=append(s2, 1,2,8,89,14,17,18)//超出容量会拷贝扩容
s2[0]=71//这时候改的还是原来和S1共有的底层数组
fmt.Println("s1=",s1)
fmt.Println("s2=",s2)
//s2=append(s2, 9,10,11,23,22,35,78,79,90,81,67,43,32,45,43,57,75,98,67,43,15,16,18,16,87,23,76,48,35,24,88,77)
// fmt.Println("s1=",s1)
// fmt.Println("s2=",s2)
}
执行结果
s1= [2 71 4 5 6]
s2= [71 4 5 6 7]
示例
package main
import (
"fmt"
)
func main(){
var a []int
for i:=0;i<20;i++{
a=append(a, i)
fmt.Printf("len:%d,cap:%d\n",len(a),cap(a))
}
}
结果
len:1,cap:1
len:2,cap:2
len:3,cap:4
len:4,cap:4
len:5,cap:8
len:6,cap:8
len:7,cap:8
len:8,cap:8
len:9,cap:16
len:10,cap:16
len:11,cap:16
len:12,cap:16
len:13,cap:16
len:14,cap:16
len:15,cap:16
len:16,cap:16
len:17,cap:32
len:18,cap:32
len:19,cap:32
len:20,cap:32
map 集合初始化与赋值
package main
import(
"fmt"
)
func main(){
//map 是key和value(值)的无序,注意查询方便
var courseMap = map[string]string{
"go":"go工程师",
"python":"python工程师",
"gin":"gin深入学习",
}
//打印map某值
fmt.Println(courseMap["go"])
//放值
courseMap["mysql"]="mysql工程师"
fmt.Println(courseMap)
//声明没有初始化不能直接使用它是nil,要想往里面存值,必须要初始化操作故:var m1 map[string]string 操作失败
var m1= map[string]string{} //{}里可以不写内存必须要有,代表初始化
m1["s1"]="T"
fmt.Println(m1)
//使用make 方法初始化;make内置函数主要初始化切片、map、channel
var m2= make(map[string]string,3)
m2["1"]="a"
fmt.Println(m2)
//使用make方法初始化2
var m3=make(map[string]string)
m3["2"]="R"
fmt.Println(m3)
}
执行结果
PS D:\golang\goproject\src\lnhgo> go run day02\demo06\main.go
go工程师
map[gin:gin深入学习 go:go工程师 mysql:mysql工程师 python:python工程师]
map[s1:T]
map[1:a]
map[2:R]
map 的遍历
package main
import(
"fmt"
)
func main(){
//map 是key和value(值)的无序,注意查询方便
var courseMap = map[string]string{
"go":"go工程师",
"python":"python工程师",
"gin":"gin深入学习",
}
for i,v:=range courseMap{
fmt.Println(i,v)
}
//只遍历key是还可以使用一下方式
for v:=range courseMap{
fmt.Println(v)
}
}
执行结果
go go工程师
python python工程师
gin gin深入学习
go
python
gin
PS D:\golang\goproje
判断map是否存在某个元素和删除元素
package main
import(
"fmt"
)
func main(){
//map 是key和value(值)的无序,注意查询方便
var courseMap = map[string]string{
"go":"go工程师",
"python":"python工程师",
"gin":"gin深入学习",
}
//判断map里是否存在key
courseMap["java"]=""
d,i:=courseMap["java"]//java 的value赋值给d
if i{
fmt.Println("map里存在java这个key")
fmt.Println(d)
}else{
fmt.Println("map里不存在java这个key")
}
courseMap["java"]="java工程师"
//d,i=courseMap["java"]//java 的value赋值给d
if d,i=courseMap["java"]; i{
fmt.Println("map里存在java这个key")
fmt.Println(d)
}else{
fmt.Println("map里不存在java这个key")
}
//删除某个元素,删除不存在的key也不报错;map不是线程安全的
delete(courseMap,"grpc")
fmt.Println(courseMap)
}
执行结果
map里存在java这个key
map里存在java这个key
java工程师
map[gin:gin深入学习 go:go工程师 java:java工程师 python:python工程师]
list 列表
package main
import (
"container/list"
"fmt"
)
func main(){
var mylist list.List//初始化1
//初始化2操作
//mylist := list.New()
mylist.PushBack("go")
mylist.PushBack("java")
mylist.PushBack("PHA")
//fmt.Println(mylist)
//正向遍历列表
for i:=mylist.Front();i!=nil;i=i.Next(){
fmt.Println(i.Value)
}
//反向遍历
for i:=mylist.Back();i!=nil;i=i.Prev(){
fmt.Println(i.Value)
}
//方式2 初始化列表
t:=list.New()
t.PushBack("t")
t.PushBack("grpc")
//头部插入
t.PushFront("JAVA")
fmt.Println("遍历T列表")
for i:=t.Front();i!=nil;i=i.Next(){
fmt.Println(i.Value)
}
//插入元素
s := t.Front()
for; s!=nil;s=s.Next(){
if s.Value.(string)== "grpc" {
break
}
}
t.InsertBefore("python",s)
fmt.Println("-----------------------")
for i:=t.Front();i!=nil;i=i.Next(){
fmt.Println(i.Value)
}
fmt.Println("-------------------")
//删除元素
for; s!=nil;s=s.Next(){
if s.Value.(string)== "grpc" {
break
}
}
t.Remove(s)
for i:=t.Front();i!=nil;i=i.Next(){
fmt.Println(i.Value)
}
}
执行结果
go
java
PHA
PHA
java
go
遍历T列表
JAVA
t
grpc
-----------------------
JAVA
t
python
grpc
-------------------
JAVA
t
python
草都可以从石头缝隙中长出来更可况你呢

浙公网安备 33010602011771号