欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-29 22:50:34
...

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

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

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

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

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

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

实验:

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的,看来完全不是这回事。。