go append 的疑问

2023-02-27 11:46:28 +08:00
 echoless
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 也要跟着变啊.

1944 次点击
所在节点    Go 编程语言
41 条回复
echoless
2023-02-27 11:49:50 +08:00
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. 草
nickchenyx
2023-02-27 11:53:06 +08:00
不然 append 为啥会返回一个新 arr 给你持有呢?最好的实践就是一直用最新的 arr 变量,别去动之前的
echoless
2023-02-27 11:53:25 +08:00
感觉是个坑啊

```
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
echoless
2023-02-27 11:55:08 +08:00
@nickchenyx #2 所谓最佳实践就是用来掩盖语言设计缺陷的.

从我不多的 golang 经验看, 这个 append 绝对咬过不少人.
beidounanxizi
2023-02-27 11:57:58 +08:00
append 是这样的 里面有个 growslice 扩容机制 memcopy 变成新数组的过程
1343EFF
2023-02-27 11:58:55 +08:00
看着像 php 的风格哈哈哈返回一个新的数组而不是让你引用旧的
echoless
2023-02-27 12:01:04 +08:00
@nickchenyx #2 我以为是在原有 arr 的基础上去扩展.

看来是

如果原来的 arr 够用, 就直接在上面扩展
不够就会新创建一个 arr(把数据 copy 过去).
beidounanxizi
2023-02-27 12:03:18 +08:00
echoless
2023-02-27 12:03:20 +08:00
@1343EFF #6 坑在于 如果原来的是容量够, 就是引用旧的. 我觉得每个 golang 程序员都要被咬一次
echoless
2023-02-27 12:04:20 +08:00
@beidounanxizi #8 多谢, 普通使用要看原理, 说明设计是不够自然.
Maboroshii
2023-02-27 12:04:31 +08:00
是这样的啊,要不然就是 array.append 方法了。而且一般写代码如果这样写,看代码的人都要晕了,一会儿旧一会儿新的。。
cmdOptionKana
2023-02-27 12:08:02 +08:00
@wuhaoecho 语言怎么设计,有得有失,比如设计成 Java 那样,确实低级坑是少一点,但内存占用就会大。

Go 希望编译速度快、运行效率高,自然就会要求程序员多费点心思。

像 C/C++, Rust 之类,低级坑更多,需要程序员耗费精神自己小心处理的地方更多,但运行效率也更高。
echoless
2023-02-27 12:10:14 +08:00
@cmdOptionKana #12 统一你的观点, 所以我觉得 golang 是比 java 更难的语言, 多了一层 pointer, 弄出来很多“似是而非”的问题.
cmdOptionKana
2023-02-27 12:15:52 +08:00
@wuhaoecho 我感觉难度差别很细微,各有各的难点,Java 也有一些很复杂的地方。

C++, Rust 是难度高得很明显,但如果 Go 和 Java 比,就算说 Go 难,但难那么一点点,几乎可以忽略不计。
hzjseasea
2023-02-27 12:16:36 +08:00
op 真的是边骂边学 golang...
MoYi123
2023-02-27 12:18:48 +08:00
@wuhaoecho 不是 go 比 java 多了指针, 而是 java 比 go 少了指针.
echoless
2023-02-27 12:19:18 +08:00
@cmdOptionKana #14 我虽然写的 java 不多, 但是不记得有什么困惑, golang 感觉老搞不清. 虽然也能写, 老觉得这样写是不是符合“标准”, java python 这些从来没有这样的困惑. rust c++ 跟 go java 不是一个层次的, 难是预期之内的.
echoless
2023-02-27 12:21:33 +08:00
@hzjseasea #15 没办法啊, 生活所迫, 我要是 python 能找到理想的工作才不会学 golang, 不过我把可以骂的点, 都搞清楚了, 就学会了么.
lesismal
2023-02-27 12:25:46 +08:00
c 时代的 realloc 就是这样的,只是那些语言为了搬砖效率封装了一大堆、然后圈养了大批 CURDer
hzjseasea
2023-02-27 12:26:39 +08:00
@wuhaoecho 我之前也是 python 转的 go,那时候还偶尔看点 rust ,当时给我的感觉就是卧槽这才是代码,python 太多东西给你封装起来 你写代码的时候压根看不见,现在把这些封装的都抛出来让你自己管理了,就觉得这也不好那也不好了... 像 go 的 map slice map channel 这四块都可以去了解下源码, 反正你找工作也要了解的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/919461

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX