GO语言容器

//GO语言容器

/*************************************************************************/
/* --> 一、数组的声明 */
var 数组变量名 [元素数量]Type // 声明数组
var a [3]int = [3]int{1, 2, 3}
q := [...]int{1, 2, 3} // 在数组长度的位置出现“...”省略号,则表示数组的长度是根据初始化值的个数来计算
p := [3]int{1, 2, 3}
p = [4]int{1, 2, 3, 4} // 编译错误:无法将 [4]int 赋给 [3]int

a := [2]int{1, 2}
b := [...]int{1, 2}
c := [2]int{1, 3}
fmt.Println(a == b, a == c, b == c) // "true false false"
d := [3]int{1, 2}
fmt.Println(a == d) // 编译错误:无法比较 [2]int == [3]int

var team [3]string // 遍历访问每一个元素
team[0] = "hammer"
team[1] = "soldier"
team[2] = "mum"
for k, v := range team {
fmt.Println(k, v)
}

/*************************************************************************/
/* --> 二、多维数组*/
// Go语言中允许使用多维数组,因为数组属于值类型,所以多维数组的所有维度都会在创建时自动初始化零值,多维数组尤其适合管理具有父子关系或者与坐标系相关联的数据。

var array_name [size1][size2]...[sizen] array_type // 声明多维数组

var array [4][2]int // 声明一个二维整型数组,两个维度的长度分别是 4 和 2
array = [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} // 使用数组字面量来声明并初始化一个二维整型数组
array = [4][2]int{1: {20, 21}, 3: {40, 41}} // 声明并初始化数组中索引为 1 和 3 的元素
array = [4][2]int{1: {0: 20}, 3: {1: 41}} // 声明并初始化数组中指定的元素

var array1 [2][2]int = [2][2]int{{1,11}, {2,22}}
var array2 [2]int = array1[1] // 将array1中的索引为1的维度复制到一个同类型的数组 11,22
var array3 int = array1[1][0] // 将array1中指定整型值复制到新的整型变量中 1

/*************************************************************************/
/* --> 三、切片slice*/
// 切片默认指向一段连续内存区域,可以是数组,也可以是切片本身
slice [开始位置 : 结束位置] // 从连续内存区域生成切片,以位置索引计算

var a = [3]int{1, 2, 3}
fmt.Println(a, a[1:2]) // 输出结果:[1 2 3] [2]
fmt.Println(a, a[:]) // 当开始和结束位置索引均为空时,生成的切片将和原切片在数据内容上一致
fmt.Println(a,a[0,0]) // 重置切片,结果为空列表

var strList []string // 声明字符串切片

make( []Type, size, cap ) // 使用make()函数构造切片
// type是指切片元素类型。size指分配多少元素。cap指预分配的元素数,这个值设定不影响size,只是提前分配空间,降低多次分配造成的性能问题
// 使用 make() 函数生成的切片一定发生了内存分配操作,但给定开始与结束位置(包括切片复位)的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作。

/*************************************************************************/
/* --> 四、为切片添加元素*/
var a []int
a = append(a, 1) // 追加1个元素
a = append(a, 1, 2, 3) // 追加多个元素, 手写解包方式
// 在使用 append() 函数为切片动态添加元素时,如果空间不足以容纳足够多的元素,切片就会进行“扩容”,此时新切片的长度会发生改变

var a = []int{1,2,3}
a = append([]int{0}, a...) // 在开头添加1个元素
a = append([]int{-3,-2,-1}, a...) // 在开头添加1个切片
// 在切片开头添加元素一般都会导致内存的重新分配,而且会导致已有元素全部被复制 1 次,因此,从切片的开头添加元素的性能要比从尾部追加元素的性能差很多

var a []int
a = append(a[:i], append([]int{x}, a[i:]...)...) // 在第i个位置插入x
a = append(a[:i], append([]int{1,2,3}, a[i:]...)...) // 在第i个位置插入切片

/*************************************************************************/
/* --> 五、切片复制*/
copy( destSlice, srcSlice []T) int

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个位置

/*************************************************************************/
/* --> 六、从切片中删除元素/
/

Go语言并没有对删除切片元素提供专用的语法或者接口,需要使用切片本身的特性来删除元素,根据要删除元素的位置有三种情况,
分别是从开头位置删除、从中间位置删除和从尾部删除,其中删除切片尾部的元素速度最快。
*/
a = []int{1, 2, 3}
a = a[1:] // 删除开头1个元素
a = a[N:] // 删除开头N个元素

a = []int{1, 2, 3}
a = append(a[:0], a[1:]...) // 删除开头1个元素
a = append(a[:0], a[N:]...) // 删除开头N个元素

a = []int{1, 2, 3}
a = a[:copy(a, a[1:])] // 删除开头1个元素
a = a[:copy(a, a[N:])] // 删除开头N个元素

// Go语言中删除切片元素的本质是,以被删除元素为分界点,将前后两个部分的内存重新连接起来
func main() {
seq := []string{"a", "b", "c", "d", "e"}
// 指定删除位置
index := 2
// 查看删除位置之前的元素和之后的元素
fmt.Println(seq[:index], seq[index+1:]) // [a b] [d e]
// 将删除点前后的元素连接起来
seq = append(seq[:index], seq[index+1:]...)
fmt.Println(seq) // [a b d e]
}

/*************************************************************************/
/* --> 七、range,循环迭代切片*/
// 创建一个整型切片,并赋值
slice := []int{10, 20, 30, 40}
// 迭代每一个元素,并显示其值
for index, value := range slice {
fmt.Printf("Index: %d Value: %d\n", index, value)
}

// range 返回的是每个元素的副本,而不是直接返回对该元素的引用
// 创建一个整型切片,并赋值
slice := []int{10, 20, 30, 40}
// 迭代每个元素,并显示值和地址
for index, value := range slice {
fmt.Printf("Value: %d Value-Addr: %X ElemAddr: %X\n", value, &value, &slice[index])
}
/*
Value: 10 Value-Addr: 10500168 ElemAddr: 1052E100
Value: 20 Value-Addr: 10500168 ElemAddr: 1052E104
Value: 30 Value-Addr: 10500168 ElemAddr: 1052E108
Value: 40 Value-Addr: 10500168 ElemAddr: 1052E10C
*/

/*************************************************************************/
/* --> 八、多维切片*/
// 声明一个二维整型切片并赋值
slice := [][]int{{10}, {100, 200}}
// 为第一个切片追加值为 20 的元素
slice[0] = append(slice[0], 20)

/*************************************************************************/
/* --> 九、map 映射/
// 类似于字典
// 和数组不同,map 可以根据新增的 key-value 动态的伸缩
var mapname map[keytype]valuetype // 声明方式,keytype指键的类型,valuetype指键对应值的类型
func main() {
var mapLit map[string]int
//var mapCreated map[string]float32
var mapAssigned map[string]int // 声明
mapLit = map[string]int{"one": 1, "two": 2} // 初始化
mapCreated := make(map[string]float32) // 初始化
mapAssigned = mapLit
mapCreated["key1"] = 4.5
mapCreated["key2"] = 3.14159
mapAssigned["two"] = 3
fmt.Printf("Map literal at "one" is: %d\n", mapLit["one"])
fmt.Printf("Map created at "key2" is: %f\n", mapCreated["key2"])
fmt.Printf("Map assigned at "two" is: %d\n", mapLit["two"])
fmt.Printf("Map literal at "ten" is: %d\n", mapLit["ten"])
}
/

1、mapCreated 的创建方式mapCreated := make(map[string]float)等价于mapCreated := map[string]float{}
2、mapAssigned 是 mapList 的引用,对 mapAssigned 的修改也会影响到 mapLit 的值
3、可以使用 make(),但不能使用 new() 来构造 map,如果错误的使用 new() 分配了一个引用对象,
会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址:mapCreated := new(map[string]float)
4、
*/

// 遍历同样使用range或者for循环
// 使用delete()函数从map中删除键值对
delete(map, 键)

// 清空map中的所有元素,GO语言中没有为map提供任何清空的函数,唯一的办法就是重新make一个新的map

/*************************************************************************/
/* --> 十、sync.Map 在并发环境中使用的map/
// Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的
// sync.Map相对于map性能有所损失,所以,在非并发的情况下使用map比较好
// 如果在非并发的情况下使用map的同时使用锁,性能则不如sync.Map
sync.Map // 和map不同,sync.Map是sync包下的特殊结构
/

sync.Map有以下几点特性
1、无需初始化,直接声明即可
2、sync.Map不能使用map的方式进行取值和设置等操作,俄日是使用sync.Map的方法进行调用
Store表示存储,Load表示获取。Delete表示删除
3、使用Range配合一个回调函数进行遍历操作,通过回调函数返回内部遍历出来的值,
Range参数中回调函数的返回值在需要继续迭代遍历时,返回true,终止迭代遍历时,返回false
/
func main() {
var scene sync.Map
// 将键值对保存到sync.Map
scene.Store("greece", 97)
scene.Store("london", 100)
scene.Store("egypt", 200)
// 从sync.Map中根据键取值
fmt.Println(scene.Load("london")) // 100 true
// 根据键删除对应的键值对
scene.Delete("london")
// 遍历所有sync.Map中的键值对
scene.Range(func(k, v interface{}) bool {
fmt.Println("iterate:", k, v) // iterate: egypt 200 iterate: greece 97
return true
})
}
/

Range方法可以遍历sync.Map,但遍历需要提供一个匿名函数,参数为 k、v,类型为 interface{},
每次 Range() 在遍历一个元素时,都会调用这个匿名函数把结果返回。
Range 参数中回调函数的返回值在需要继续迭代遍历时,返回 true,终止迭代遍历时,返回 false
*/

/*************************************************************************/
/* --> 十一、列表/
/

1、列表初始化,分别可以使用New()函数和var关键字,两者效果一致
2、列表与切片和map不同的是,列表没有具体元素类型的限制。风险:放入一个interface{}类型的值,
取出后如果将interface{}转换为其他类型将会发生宕机
3、go语言中的列表为双链表类型的,支持从队列前后插入元素,PushFront和PushBack
4、上面两个方法都会返回一个*list.Element结构,如果需要删除之前插入的元素,则只能通过
*list.Element配合Remove()方法删除
*/
l := list.New() // 初始化一个空列表
l.PushBack("fist") // 将字符串插入列表尾部
l.PushFront(67) // 将字符串插入列表头部

func main() {
l := list.New()

l.PushBack("canon")  // 尾部添加

l.PushFront(67)  // 头部添加

element := l.PushBack("fist")  // 尾部添加后保存元素句柄

l.InsertAfter("high", element)  // 在fist之后添加high

l.InsertBefore("noon", element)  // 在fist之前添加noon

l.Remove(element)  // 移除element对应的元素

}

// 遍历列表
l := list.New()
l.PushBack("canon") // 尾部添加
l.PushFront(67) // 头部添加
for i := l.Front(); i != nil; i = i.Next() {
fmt.Println(i.Value)
}
/*
使用 for 语句进行遍历,其中 i:=l.Front() 表示初始赋值,只会在一开始执行一次,
每次循环会进行一次 i != nil 语句判断,如果返回 false,表示退出循环,反之则会执行 i = i.Next()
*/

/*************************************************************************/
/* --> 十二、make和new关键字的区别及实现原理*/
// new 函数,它返回的永远是类型的指针,指针指向分配类型的内存地址
// 内置类型数据分配内存
var sum *int
sum = new(int) //分配空间
sum = 98
fmt.Println(
sum)

// 自定义类型new
type Student struct {
name string
age int
}
var s *Student // 声明一个指针s
s = new(Student) //分配空间
s.name ="dequan"

// make只用于 chan、map 以及 slice 的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容