go语言数组和切片的深度对比
程序员文章站
2024-01-29 22:50:34
...
首先说下,数组和切片由于语法十分相似,在使用中容易混淆,要认真区分。实际上数组和切片是两种完全不同的类型。
版本是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的,看来完全不是这回事。。
上一篇: Go语言中的数组、切片和字符串
下一篇: Go语言中数组和切片的用法