go语言数组和切片的深度对比

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/vrg000/article/details/82225706

首先说下,数组和切片由于语法十分相似,在使用中容易混淆,要认真区分。实际上数组和切片是两种完全不同的类型。
版本是go-1.6,没有用最新的,可能新版本会对go有所优化把。

var a [3]string     //数组
var b []string      //切片

从语法上来看,数组遵循传统的三要素 – 名称、类型、长度。
而切片只有名称、类型,这意味着切片是不定长的。

从内存的角度来看,数据是一整块连续的、固定长度、固定位置的内存。
而切片则是一个指针,指向一块内存,当容量不够时就开辟更大的内存。
因此,数组还是传统意义上的数据,而切片则更类似于C++中的vector。

这里写图片描述
这里写图片描述

数组使用时的注意点:
数组的赋值代价是非常大的,相当于把一块内存完全拷贝。
切片使用时的注意点:
切片结构中使用了指针,存在深拷贝问题。

实验:

package main

import (
    "fmt"
)

func main() {
    //切片
    a := []string{"aaa", "bbb", "ccc"}
    b := a
    a[0] = "aaa"
    a[1] = "ccc"
    fmt.Println(a, b, &a[0], &b[0])
    //数组
    f := [3]string{"aaa", "bbb", "ccc"}
    g := f
    fmt.Println(f, g, &f[0], &g[0])
    //互相赋值会报错
    //a = f
    //./main.go:20: cannot use f (type [3]string) as type []string in assignment
    //内存
    c := "aaa"
    d := "aaa"
    fmt.Println(&c, &d)
}

结果:

[aaa ccc ccc] [aaa ccc ccc] 0xc82000c120 0xc82000c120 //切片
[aaa bbb ccc] [aaa bbb ccc] 0xc82000c150 0xc82000c180 //数组
0xc82000a380 0xc82000a390 //字符串指针

由此可见,切片确实是浅拷贝的。而数组则不存在这样的问题。
另外切片和数组是两种不同类型,不能互相赋值。
最后测试了一下字符串,发现和C中的字符串不一样。C中这两个字符串应该指向同一块内存的。记得学C的时候,C中的字符串叫字面值常量,存储在常量区。至于go的不是太清楚了。不过感觉有点浪费。

C字符串实验:

#include <stdio.h>

int main()
{
    char *a = "aaa";
    char *b = "aaa";
    printf("%p,%p\n", a, b);
    printf("Hello world\n");
    return 0;
}

结果:

0x400634,0x400634
Hello world

append函数到底做了什么?
执行如下代码:

    h := []string{"aaa"}
    h2 := append(h, "bbb")
    fmt.Println(&h[0], &h2[0])

结果:

0xc82000a3a0 0xc82000e1a0

貌似就是新开辟了一块内存额,记得C中有realloc的,看来完全不是这回事。。

猜你喜欢

转载自blog.csdn.net/vrg000/article/details/82225706