golang之数组,slice,map

lesou · · 7040 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。



一 、==========================array 数组===================================

    索引只能是 int 整数型 所以不管几维数组 索引都是 整数  slice 是动态数组 索引也是 整数型 map为key 所以 可以为 整数 也可以为 字符串型

    注意slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度,而声明slice时,方括号内没有任何字符。

arr1 := [10]int{1,2,3,4} //数组,长度为10,只有4个元素指定,其它的元素值默认为0

arr2 := [...]string{"a","b","c"} //数组,长度自适应,这里长度为3

s1 := []int{1,2,3,4} //slice,目前长度为4,可能通过append来动态添加元素个数


数组声明 方式

arr1 := [10]int{1,2,3,4} //数组,长度为10,只有4个元素指定,其它的元素值默认为0

里面索引为 0:1  1:2  2:3  3:4  4:0  5:0  .....  9:0


arr1 := [10]string{"1","2","3","4"} //数组,长度为10,只有4个元素指定,其它的元素值默认为"" 空字符串

里面索引为 0:"1"  1:"2"  2:"3"  3:"4"  4:"0"  5:""  .....  9:""


arr2 := [...]string{"a","b","c"} //数组,长度自适应,这里长度为3

arr3 := make([]int, 10)  // make 为创建内存  长度为10  元素都为 0


var arr4 [5]int

arr4[0] = 9

arr4=[5]int{5,5,5}  // [5 5 5 0 0]


可以用 new() 创建数组,返回数组指针。

func test(a *[10]int) {

    a[2] = 100   // 用指针直接操作没有压力。

}

func main() {

    var a = new([10]int)   // 返回指针。

    test(a)

    fmt.Println(a, len(a))

}

输出结果:


&[0 0 100 0 0 0 0 0 0 0] 10



多维数组 


a := [2][2]int{ {1,2}, {3,4} }

b := [2][2]str{ {"1","2"}, {"3","4"} }


func main() {

    var a = [3][2]int{ [...]int{1, 2}, [...]int{3, 4} }

    var b = [3][2]int{ {1, 2}, {3, 4} }

    c := [...][2]int{ {1, 2}, {3, 4}, {5, 6} }   // 第二个维度不能用 "..." 。

    c[1][1] = 100

    fmt.Println(a, "\n", b, "\n", c, len(c), len(c[0]))

}


数组比较

println([1]string{"a"} == [1]string{"a"})


数组是值类型,也就是说会拷贝整个数组内存进行值传递。可用 slice 或指针代替。


二 、 ==========================slice 切片===================================

    切片就是数组取其中的部分就为切片为取出的数组数值的指针集合。


    数组  索引只能是 int 整数型 所以不管几维数组 索引都是 整数  slice 是动态数组 索引也是 整数型 map为key 所以 可以为 整数 也可以为 字符串型

    注意slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度,而声明slice时,方括号内没有任何字符。


切片声明

s := []int{ 0, 1, 2 }


不能使用 new(),而应该是 make([]T, len, cap)。因为除了分配内存,还需要设置相关的属性。如

果忽略 cap 参数,则 cap = len 。


func main() {

    s1 := make([]int, 10)  // 相当于 [10]int{...}[:]

    s1[1] = 100

    fmt.Println(s1, len(s1), cap(s1))

    s2 := make([]int, 5, 10)

    s2[4] = 200

    fmt.Println(s2, len(s2), cap(s2))

}

输出:


[0 100 0 0 0 0 0 0 0 0] 10 10

[0 0 0 0 200] 5 10


可以用 append() 向 slice 尾部添加新元素,这些元素保存到底层数组。append 并不会影响原 slice的属性,它返回变更后新的 slice 对象。如果超出 cap 限制,则会重新分配底层数组。


==========================Maps 字典===================================

引用类型,类似 Python dict ,不保证 Key/Value 存放顺序。Key 必须是支持比较运算符 (== 、!=)的类型。如 number 、string 、pointer、array、struct 、interface (接口实现类型必须支持比较运算符),不能是 function、map、slice。

map 查找操作比线性搜索快很多,但比起用序号访问 array、slice,大约慢 100x 左右。绝大多数时候,其操作性能要略好于 Python Dict 、C++ Map。


func test(d map[string]int) {

    d["x"] = 100

}

func main() {

    var d = map[string]int{ "a":1, "b":2 };

    d2 := map[int]string{ 1:"a", 2:"b" };

    test(d)

    fmt.Println(d, d2)

    d3 := make(map[string]string)

    d3["name"] = "Jack"

    fmt.Println(d3, len(d3))

}

输出:


map[a:1 b:2 x:100] map[1:a 2:b]

map[name:Jack] 1



使 array/struct key 的例子。


type User struct {

    Name string

}

func main() {

    a := [2]int{ 0, 1}

    b := [2]int{ 0, 1}

    d := map[[2]int]string { a: "ssss" }

    fmt.Println(d, d[b])

    u := User{ "User1" }

    u2 := u

    d2 := map[User]string { u: "xxxx" }

    fmt.Println(d2, d2[u2])

}

输出:


map[[0 1]:ssss] ssss

map[{User1}:xxxx] xxxx



value 的类型就很自由了,完全可以用匿名结构或者空接口。


type User struct {

    Name string

}

func main() {

    i := 100

    d := map[*int]struct{ x, y float64 } { &i: { 1.0, 2.0 } }

    fmt.Println(d, d[&i], d[&i].y)

    //d2 := map[interface{}]string { "a": "1", 1:"ssssss" }

    d2 := map[string]interface{} { "a": 1, "b": User{ "user1" } }

    fmt.Println(d2, d2["b"].(User).Name)

}

输出:


map[0x42132018:{1 2}] {1 2} 2

map[a:1 b:{user1}] user1



使用 make() 创建 map 时,提供一个合理的初始容量有助于减少后续新增操作的内存分配次数。在需要时,map 会⾃动扩张容量。

常用的判断和删除操作:


func main() {

    var d = map[string]int{ "a":1, "b":2 };

    v, ok := d["b"]  // key b 存在,v = ["b"], ok = true

    fmt.Println(v, ok)

    v = d["c"]  // key c 不存在,v = 0 (default)

    fmt.Println(v)  // 要判断 key 是否存在,建议用 ok idiom 模式。

    d["c"] = 3   // 添加或修改

    fmt.Println(d)

    delete(d, "c")  // 删除。删除不存在的 key,不会引发错误。

    fmt.Println(d)

}

输出:


2 true

0 false

map[a:1 c:3 b:2]

map[a:1 b:2]



迭代器用法:

The Go 1 .1 hashmap iteration starts at a random bucket. However, it stores up to 8 key/value pairs in a bucket.

And within a bucket, hashmap iteration always returns the values in the same order .


func main() {

    d := map[string]int{ "a":1, "b":2 };

    for k, v := range d {  // 获取 key, value

        println(k, "=", v)

    }

    for k := range d {  // 仅获取 key

        println(k, "=", d[k])

    }

}

通过 map[key] 返回的只是一个 "临时值拷贝",修改其自身状态没有任何意义,只能重新 value 赋值或改用指针修改所引用的内存。


type User struct {

    Id int

    Name string

}

func main() {

    users := map[string]User{

        "a": User{1, "user1"},

    }

    fmt.Println(users)

    // Error: cannot assign to users["a"].Name

    //users["a"].Name = "Jack"

    // 重新 value 赋值

    u := users["a"]

    u.Name = "Jack"

    users["a"] = u

    fmt.Println(users["a"])

    // 改⽤指针类型

    users2 := map[string]*User{

        "a2": &User{2, "user2"},

    }

    users2["a2"].Name = "Tom"

    fmt.Println(users2["a2"])

}

输出:


map[a:{1 user1}]

{1 Jack}

&{2 Tom}



可以在 for range 迭代时安全删除和插入新的字典项。


func main() {

    d := map[string]int { "b":2, "c":3, "e":5 }

    for k, v := range d {

        println(k, v)

        if k == "b" { delete(d, k) }

        if k == "c" { d["a"] = 1 }

    }

    fmt.Println(d)

}

输出:


c 3

b 2

e 5

map[a:1 c:3 e:5]



注:map 作为参数时,直接复制指针。



有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:lesou

查看原文:golang之数组,slice,map

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

7040 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传