Golang Go语言中结构体切片,大家的习惯是切片元素是结构体值还是指针(不考虑性能,仅考虑代码优雅)

发布于 1周前 作者 eggper 来自 Go语言

Golang Go语言中结构体切片,大家的习惯是切片元素是结构体值还是指针(不考虑性能,仅考虑代码优雅)

type Foobar struct {
}

切片元素是值

var s []Foobar

Or:

切片元素是指针

var s []*Foobar

不考虑性能,仅考考代码优雅性。

前一种切片(元素为值)在循环赋值时有不便之处:

for _, i := range s {
	i.xxx = yyy
}

上面的代码实际上是无效的,必须使用索引,于是代码很不优雅:

for i, _ := range s {
	s[i].xxx = yyy
}

但后一种切片(元素为指针),在很多使用场景下同样不方便


更多关于Golang Go语言中结构体切片,大家的习惯是切片元素是结构体值还是指针(不考虑性能,仅考虑代码优雅)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

21 回复

后一种切片(元素为指针),在很多使用场景下同样不方便。

在使用切片中的某元素时,常常要先解引用(就是说需要写成类似 *s[i] 的形式而非 s[i]),感觉同样很不优雅

更多关于Golang Go语言中结构体切片,大家的习惯是切片元素是结构体值还是指针(不考虑性能,仅考虑代码优雅)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


<br>for _, i := range s {<br> <a target="_blank" href="http://i.xxx" rel="nofollow noopener">i.xxx</a> = yyy<br>}<br>
其他语言这样也不行呀。
我是用这种。

我比较习惯指针,可能是因为我之前写了好几年的 C++吧

一律优先用指针,遇到特殊情况才直接用结构体。

另外在 Go 里,给一个结构体添加方法,官方也是提倡优先对其指针添加方法,像这样 func (foobar *Foobar) Method(){}

我是用上面那种

range 是复制到一个新的对象去了,你再修改也改不到原始的

别问,问就是指针

喜欢用值类型,虽然指针和值类型在传值修改的影响完全不一样,根据使用场景的不同,各自有各自的优势或者说弊端吧。值类型完全不用考虑内存管理的问题

用指针,性能即优雅。 就像我声明切片的时候尽量指定容量,看着更舒服。

指针性能未必更好. 要考虑 gc 和内存分配这些问题.

在有 gc 的语言中一切常识都要重新考虑。

一个指针数组填充时需要 N 次内存分配,创建 N + 1 个对象。

写起来奔放的话 gc 导致的 cpu 使用会比程序真正用到的还要多。

STW 延迟还好,但是吞吐量就没有了。

所以为啥要加个_, for i := range s {s[i].xxx = yyyy} 也挺好看的啊

for i := range s {
s[i].xxx = yyy
}

看情况, 小对象直接存值; 大对象一般存指针; 若大对象且频繁创建销毁看情况, 若内存足够直接存值, 若内存紧张存指针, 总之就是 trade-off

因为切片底层的扩容是根据切片元素分情况的, 值 or 指针. 若是值直接扩容追加到旧内存; 若是指针, 需要判断是否写屏障, 还有 gc 判断啥的, 因此对增加开销.

无脑指针即可

99%指针
1%为了性能才用 struct

尽量指针,
极个别为了性能考虑保存为值,但是使用时也尽量使用指针:

<br> list1 := make([]Struct1, 1)<br><br> for i, _ := range list1 {<br> v := &amp;list1[i]<br><br> v.A = "11"<br> }<br>

是否考虑过为什么 range 获取到的元素是元素的一个复制?为什么 go 语言要如此设计?人家特地复制出来给你用就怕你瞎改。老老实实写 s[i].xxx = yyy 吧。
另外:slice[1] = a;slice[1]被放入的是 a 的一个复制,但是使用 slice[1]获取值时获取的是底层值,因此可以直接进行 slice[1].xx =b 。 而 map[1]=a,而获取的时候总是返回 map[1]底层值的一个复制,因此无法 map[1].xx=b 。

在Golang中,对于结构体切片的选择——切片元素是结构体值还是指针,这实际上是一个在代码风格和可维护性上值得深入探讨的话题。在不考虑性能差异的前提下,我们主要关注代码的优雅性。

使用结构体值作为切片元素,可以使代码更加直观和简洁。每个切片元素都直接存储了结构体的完整数据,无需通过指针解引用来访问成员,这在处理小规模数据时尤为方便。此外,使用值传递可以避免一些潜在的指针操作错误,使得代码更加健壮。

然而,使用指针作为切片元素也有其优势。指针允许我们直接修改切片中的元素而无需返回或传递额外的值,这在处理大型结构体或需要频繁修改数据的场景中非常有用。此外,指针还可以用于表示可选值或空值,这在某些设计模式中可能更加灵活。

综合考虑代码优雅性,我认为选择主要取决于具体的应用场景。如果结构体较小且不需要频繁修改,使用结构体值作为切片元素可能更加直观和简洁。如果结构体较大或需要频繁修改,使用指针可能更加灵活和高效。

总的来说,在Golang中编写优雅的代码需要权衡各种因素,包括可读性、可维护性和性能等。在选择结构体切片元素类型时,我们应该根据具体的应用需求和上下文来做出最佳决策。

回到顶部