Go中*[]Type与[]*Type的区别及元素取值(附C语言类比)
详解Go中[]Person与[]Person的差异(附C语言类比)
首先先修正一下你给出的Go结构体定义(Go里结构体必须用struct关键字,而且首字母大写的字段才能被包外访问,小写字段是包内私有):
type Person struct { Name string Age int // 这里把age改成Age,方便外部访问 } type People struct { City string List []*Person // 切片元素是Person指针 } type People2 struct { City string List *[]Person // 指向Person切片的指针 }
1. []*Person 是什么?怎么获取元素?
含义
[]*Person 是一个切片,切片中的每个元素都是指向Person结构体的指针。
用C语言类比的话,这就相当于你在C里定义的动态指针数组:
// 假设已经malloc分配了足够的内存 Person** list = (Person**)malloc(10 * sizeof(Person*));
每个list[i]都是一个Person*指针,可以指向栈上或者堆上的Person实例。
获取元素值
因为切片里的元素是指针,你可以直接通过索引访问指针,然后用.(Go会自动解引用指针)获取字段:
// 假设people是People类型的实例,且List已经有元素 name := people.List[0].Name age := people.List[0].Age // 等价于显式解引用:(*people.List[0]).Name
如果你要修改Person的字段,直接修改就行,因为操作的是指针指向的原实例,会影响底层对象。
2. *[]Person 是什么?怎么获取元素?
含义
*[]Person 是一个指向Person类型切片的指针。
首先要知道:Go的切片本身是一个包含三个字段的结构体(类比C的自定义结构体):
// 模拟Go切片的C结构体 typedef struct { Person* data; // 指向底层数组的指针 int len; // 切片长度 int cap; // 切片容量 } GoSlice;
那么*[]Person就相当于C里的GoSlice*——也就是指向这个切片结构体的指针,而不是指向底层数组的指针。
获取元素值
你需要先解引用指针拿到切片本身,再通过索引访问里面的Person值:
// 假设people2是People2类型的实例,且List已经指向一个有效的切片 name := (*people2.List)[0].Name age := (*people2.List)[0].Age
这里必须先解引用指针(*people2.List)得到切片,才能用索引访问元素。如果要修改切片的长度(比如append扩容),或者替换整个切片,就需要用这个指针,否则修改的只是切片的副本。
核心差异总结
| 类型 | 本质 | C语言类比 | 常见使用场景 |
|---|---|---|---|
[]*Type | 元素为指针的切片 | Type**(指针数组) | 需要存储多个独立的Type实例,修改实例字段会直接生效 |
*[]Type | 指向Type切片的指针 | 指向切片结构体的指针 | 需要修改切片本身(比如append扩容、替换整个切片),或者在函数中传递切片避免拷贝 |
简单说:[]*Type是“装着指针的切片”,*[]Type是“指向切片的指针”,两者完全不是一回事。
内容的提问来源于stack exchange,提问作者Alex T. Liu
相关产品推荐
相关产品推荐

