Golang Go语言中 append 的疑问
package main
import “fmt”
func main() {
// create a slice from an array
x := [3]string{“A”, “B”, “С”}
s := x[:] // a slice referencing the storage of x
// x[1] = “O”
t := append(s, “D”) // append items to slice s
x[1] = “O”
fmt.Println("%+v", x)
fmt.Println("%+v", s)
fmt.Println("%+v", t)
}
https://go.dev/play/p/g-eGRJLteAH
t 为什么是 [A B С D]
我的理解是 t 在 s 的基础上加了个‘D' , x 改了 s, t 也要跟着变啊.
Golang Go语言中 append 的疑问
更多关于Golang Go语言中 append 的疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
https://pkg.go.dev/builtin#append
The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice. It is therefore necessary to store the result of append, often in the variable holding the slice itself:
If it does not, a new underlying array will be allocated. 草
更多关于Golang Go语言中 append 的疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
不然 append 为啥会返回一个新 arr 给你持有呢?最好的实践就是一直用最新的 arr 变量,别去动之前的
感觉是个坑啊
```
package main
import “fmt"
func main() {
// create a slice from an array
x := make([]string, 3, 10)
x[0] = “A”
x[1] = “B”
x[2] = “C”
s := x[:] // a slice referencing the storage of x
t := append(s, “D”) // append items to slice s
x[1] = “O”
fmt.Println(”%+v", x)
fmt.Println("%+v", s)
fmt.Println("%+v", t)
}
````
https://go.dev/play/p/MLJ9L4o7UQq
#2 所谓最佳实践就是用来掩盖语言设计缺陷的.
从我不多的 golang 经验看, 这个 append 绝对咬过不少人.
append 是这样的 里面有个 growslice 扩容机制 memcopy 变成新数组的过程
#2 我以为是在原有 arr 的基础上去扩展.
看来是
如果原来的 arr 够用, 就直接在上面扩展
不够就会新创建一个 arr(把数据 copy 过去).
#6 坑在于 如果原来的是容量够, 就是引用旧的. 我觉得每个 golang 程序员都要被咬一次
#8 多谢, 普通使用要看原理, 说明设计是不够自然.
是这样的啊,要不然就是 array.append 方法了。而且一般写代码如果这样写,看代码的人都要晕了,一会儿旧一会儿新的。。
语言怎么设计,有得有失,比如设计成 Java 那样,确实低级坑是少一点,但内存占用就会大。
Go 希望编译速度快、运行效率高,自然就会要求程序员多费点心思。
像 C/C++, Rust 之类,低级坑更多,需要程序员耗费精神自己小心处理的地方更多,但运行效率也更高。
#12 统一你的观点, 所以我觉得 golang 是比 java 更难的语言, 多了一层 pointer, 弄出来很多“似是而非”的问题.
我感觉难度差别很细微,各有各的难点,Java 也有一些很复杂的地方。
C++, Rust 是难度高得很明显,但如果 Go 和 Java 比,就算说 Go 难,但难那么一点点,几乎可以忽略不计。
op 真的是边骂边学 golang…
不是 go 比 java 多了指针, 而是 java 比 go 少了指针.
#14 我虽然写的 java 不多, 但是不记得有什么困惑, golang 感觉老搞不清. 虽然也能写, 老觉得这样写是不是符合“标准”, java python 这些从来没有这样的困惑. rust c++ 跟 go java 不是一个层次的, 难是预期之内的.
#15 没办法啊, 生活所迫, 我要是 python 能找到理想的工作才不会学 golang, 不过我把可以骂的点, 都搞清楚了, 就学会了么.
c 时代的 realloc 就是这样的,只是那些语言为了搬砖效率封装了一大堆、然后圈养了大批 CURDer
我之前也是 python 转的 go,那时候还偶尔看点 rust ,当时给我的感觉就是卧槽这才是代码,python 太多东西给你封装起来 你写代码的时候压根看不见,现在把这些封装的都抛出来让你自己管理了,就觉得这也不好那也不好了… 像 go 的 map slice map channel 这四块都可以去了解下源码, 反正你找工作也要了解的
#15 https://www.v2ex.com/t/919283#reply22
看了这个我真是…
这阵容估计只有 c++ 可以一拼了吧.
> 不是 go 比 java 多了指针, 而是 java 比 go 少了指针.
这话说的妙极了
#20 大佬你适合去搞汇编
https://books.studygolang.com/GoExpertProgramming/chapter01/1.2-slice.html
https://go.dev/play/p/mgax2-QsRKI
package main
import (
“fmt”
)
func AddElement(slice []int, e int) []int {
return append(slice, e)
}
func main() {
var slice []int
slice = append(slice, 1, 2, 3)
newSlice := AddElement(slice, 4)
fmt.Println(&slice[0] == &newSlice[0])
}
专家都搞不清
我一个新手很快能摸到坑也是不容易.
设计成 OOP 风格明显会更好,之所以没有大概是因为泛型
学过 c 的就感觉很自然,类似 realloc 的行为
less is more go 语言的爹经常说的
像 rust 的 ownership 一样,自己制定一些规则,例如只能通过一个 owner slice append ,append 以后其它相关 slice 都失效。
为什么觉得是圈养了 curder 而不是技术发展提高了生产力了?现在没人钻木取火了吧?
因为 slice 底下是固定大小的数组,不够了要扩容+copy ,你可以试试用 make 来指定底层数组的大小,只要不超过这个大小就不会出现问题。
但归根结底,不知道这个就容易踩坑。
go 爹说的没毛病,我的这个 id (les is mal)也是 less is more 缩写拼接变换得到的
很多人嘲讽 go 大道至简,殊不知是他们习惯了搬砖的工作、而 go 不是只为了简单搬砖。。。
先走出自己的舒适区,然后不知不觉就破境了
你看 #19 我那句的完整顺序:
1. 先说的 “为了搬砖效率” —— 这个就是提高了部分生产力,因为提高的主要是开发效率 /速度、性能和软硬件消耗的成本是不划算的
2. 然后才说的“圈养了大批 CURDer”
科技线的演化规律通常是不同技术潮涨潮落逐步更迭到更好的,相比于 java ,go 的性能和消耗更友好,目前在一些其他语言舒适区使用者眼里,go 开发效率差很多,但毕竟出生的晚,随着逐步完善、开发效率越来越高,而且就我自己而言从来没觉得用 go 比用其他语言开发效率低。
但 go 性能不够强,只能做第二梯队、在开发效率与性能消耗之前均衡,在 CURD 与基础设施以及这两者的一些中间过渡领域会有很多作为。
往远一点看,rust 会大量占市场,目前阶段是 rust 已经进入,比如 linux 内核,比如 tidb 这种搞数据库的,比如 cloudflare 的一些基础设施:
https://mp.weixin.qq.com/s/1dB4P54tVz-aM2iYIkE4fg
再往远一点看,AI 的发展,未来大部分代码可能会是由 AI 直接生成更高性能的机器码,等到 NLP 、AI 编码更牛逼了,人类需求直接丢给 AI 了,配合上更丰富完善的测试验收体系。全盘丢给 AI 怕它作恶像终结者那样反噬人类,所以你看,OpenAI 的核心宗旨在于“实现安全的通用人工智能(AGI)”,使其有益于人类
性能是效率的永恒核心,是生产力的核心,现阶段你觉得够用了,并不代表其他人、next gen 也觉得性能够用。所以不要觉得 java 那些提高了生产力就没必要 go 和 rust 了,那只是 CURDer 这些不需要性能的人在坐井观天或者自欺欺人罢了
go rust 或者 c/cpp ,不是钻木取火。
如果这些是钻木取火,未来 AI 写代码成熟了,那时候的人同样也会说用 java php 这些是钻木取火、谁还自己写代码啊!?
过去这十几年,IT 这条线发展太快了,不知道 AI 迭代的速度会有多快,有生之年是否能见识到机器生命雏形甚至更高阶一点:joy:
不扩容之前,slice 指向底层的 array 不会变,扩容之后就变了
所以不建议 x := [3]string{“A”, “B”, “С”}这么用
一开始就 x:=[]string{},之后 append 也是 x=append(x,…)
#35 https://go.dev/play/p/tMshcyKhLSU 用 x := []string{“A”, “B”, “С”} 结果是一样的.
你别光看前半句不看后半句啊…
别误会。。我不是说 java 很好,我不仅说 go 是钻木取火,java ,rust 也是。连无穷整型都不是 builtin 的,都是比胶水 python 低一个层次的抽象。
性能和开发效率的极致得占一个吧~而不是像 go
#39 现在这些语言就是 features 取舍的组合, go 我觉得就是宣传过头, 做一些 infra 的工具还行. 大公司做一些高并发啥的也可以理解, 小公司跟风上 go 去写 crud 感觉是无法理解的(动不动 BAT 谁谁都用了, nnd 是处理一样的问题么).
哪天 chatgpt, copilot 能写代码的时候, 估计又有高级程序员跳出来说, xxx 圈养了一堆 crud 都不懂, 只会 prompt 的 XX.
关于Go语言中append
函数的疑问,这是一个在使用Go进行编程时经常会遇到的问题。append
是Go内置的一个切片操作函数,用于向切片追加元素。这里有几个关键点可以帮助你更好地理解append
的行为:
-
容量与长度:
append
会尝试在切片的现有容量内添加元素。如果容量足够,append
只会在切片末尾添加元素并更新长度。如果容量不足,append
会分配一个更大的底层数组,并将现有元素复制到新数组中,然后添加新元素。 -
返回值:
append
返回一个新的切片(尽管底层数组可能是原来的,也可能是新分配的)。这意味着如果你不使用append
的返回值,你可能会错过新添加的元素或潜在的底层数组重新分配。 -
性能考虑:由于
append
可能会触发底层数组的重新分配,频繁的小规模append
操作可能会导致性能问题。在可能的情况下,预分配足够的切片容量或使用make
函数初始化一个具有足够容量的切片,可以避免不必要的内存分配。 -
并发安全:
append
不是并发安全的。在多个goroutine中同时对一个切片进行append
操作会导致数据竞争和未定义行为。如果需要在并发环境中操作切片,应使用适当的同步机制。
总之,append
是Go中处理动态数组的强大工具,但理解其行为和潜在的性能影响对于编写高效、可靠的Go程序至关重要。希望这些信息能帮助你更好地使用append
函数。