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 也要跟着变啊.
1
echoless OP 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. 草 |
2
nickchenyx 2023-02-27 11:53:06 +08:00 via Android
不然 append 为啥会返回一个新 arr 给你持有呢?最好的实践就是一直用最新的 arr 变量,别去动之前的
|
3
echoless OP 感觉是个坑啊
``` 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 |
4
echoless OP |
5
beidounanxizi 2023-02-27 11:57:58 +08:00 1
append 是这样的 里面有个 growslice 扩容机制 memcopy 变成新数组的过程
|
6
1343EFF 2023-02-27 11:58:55 +08:00
看着像 php 的风格哈哈哈返回一个新的数组而不是让你引用旧的
|
7
echoless OP |
8
beidounanxizi 2023-02-27 12:03:18 +08:00
|
10
echoless OP @beidounanxizi #8 多谢, 普通使用要看原理, 说明设计是不够自然.
|
11
Maboroshii 2023-02-27 12:04:31 +08:00
是这样的啊,要不然就是 array.append 方法了。而且一般写代码如果这样写,看代码的人都要晕了,一会儿旧一会儿新的。。
|
12
cmdOptionKana 2023-02-27 12:08:02 +08:00 1
@wuhaoecho 语言怎么设计,有得有失,比如设计成 Java 那样,确实低级坑是少一点,但内存占用就会大。
Go 希望编译速度快、运行效率高,自然就会要求程序员多费点心思。 像 C/C++, Rust 之类,低级坑更多,需要程序员耗费精神自己小心处理的地方更多,但运行效率也更高。 |
13
echoless OP @cmdOptionKana #12 统一你的观点, 所以我觉得 golang 是比 java 更难的语言, 多了一层 pointer, 弄出来很多“似是而非”的问题.
|
14
cmdOptionKana 2023-02-27 12:15:52 +08:00
@wuhaoecho 我感觉难度差别很细微,各有各的难点,Java 也有一些很复杂的地方。
C++, Rust 是难度高得很明显,但如果 Go 和 Java 比,就算说 Go 难,但难那么一点点,几乎可以忽略不计。 |
15
fo0o7hU2tr6v6TCe 2023-02-27 12:16:36 +08:00
op 真的是边骂边学 golang...
|
17
echoless OP @cmdOptionKana #14 我虽然写的 java 不多, 但是不记得有什么困惑, golang 感觉老搞不清. 虽然也能写, 老觉得这样写是不是符合“标准”, java python 这些从来没有这样的困惑. rust c++ 跟 go java 不是一个层次的, 难是预期之内的.
|
18
echoless OP @hzjseasea #15 没办法啊, 生活所迫, 我要是 python 能找到理想的工作才不会学 golang, 不过我把可以骂的点, 都搞清楚了, 就学会了么.
|
19
lesismal 2023-02-27 12:25:46 +08:00
c 时代的 realloc 就是这样的,只是那些语言为了搬砖效率封装了一大堆、然后圈养了大批 CURDer
|
20
fo0o7hU2tr6v6TCe 2023-02-27 12:26:39 +08:00
@wuhaoecho 我之前也是 python 转的 go,那时候还偶尔看点 rust ,当时给我的感觉就是卧槽这才是代码,python 太多东西给你封装起来 你写代码的时候压根看不见,现在把这些封装的都抛出来让你自己管理了,就觉得这也不好那也不好了... 像 go 的 map slice map channel 这四块都可以去了解下源码, 反正你找工作也要了解的
|
21
echoless OP |
24
echoless OP 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]) } 专家都搞不清 我一个新手很快能摸到坑也是不容易. |
25
Nazz 2023-02-27 13:23:22 +08:00 via Android
设计成 OOP 风格明显会更好,之所以没有大概是因为泛型
|
26
hsfzxjy 2023-02-27 13:31:40 +08:00 via Android
学过 c 的就感觉很自然,类似 realloc 的行为
|
28
leonshaw 2023-02-27 13:43:32 +08:00
像 rust 的 ownership 一样,自己制定一些规则,例如只能通过一个 owner slice append ,append 以后其它相关 slice 都失效。
|
30
lanlanye 2023-02-27 14:29:01 +08:00
因为 slice 底下是固定大小的数组,不够了要扩容+copy ,你可以试试用 make 来指定底层数组的大小,只要不超过这个大小就不会出现问题。
但归根结底,不知道这个就容易踩坑。 |
31
lesismal 2023-02-27 14:29:54 +08:00
@wuhaoecho
go 爹说的没毛病,我的这个 id (les is mal)也是 less is more 缩写拼接变换得到的 很多人嘲讽 go 大道至简,殊不知是他们习惯了搬砖的工作、而 go 不是只为了简单搬砖。。。 |
32
lesismal 2023-02-27 14:31:08 +08:00
先走出自己的舒适区,然后不知不觉就破境了
|
33
lesismal 2023-02-27 14:51:54 +08:00
@zagfai
你看 #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 这些不需要性能的人在坐井观天或者自欺欺人罢了 |
34
lesismal 2023-02-27 14:57:00 +08:00
@zagfai
go rust 或者 c/cpp ,不是钻木取火。 如果这些是钻木取火,未来 AI 写代码成熟了,那时候的人同样也会说用 java php 这些是钻木取火、谁还自己写代码啊!? 过去这十几年,IT 这条线发展太快了,不知道 AI 迭代的速度会有多快,有生之年是否能见识到机器生命雏形甚至更高阶一点:joy: |
35
pkoukk 2023-02-27 18:39:23 +08:00 1
不扩容之前,slice 指向底层的 array 不会变,扩容之后就变了
所以不建议 x := [3]string{"A", "B", "С"}这么用 一开始就 x:=[]string{},之后 append 也是 x=append(x,...) |
36
echoless OP @pkoukk #35 https://go.dev/play/p/tMshcyKhLSU 用 x := []string{"A", "B", "С"} 结果是一样的.
|
38
echoless OP |
39
zagfai 2023-02-28 12:31:36 +08:00 1
@lesismal 别误会。。我不是说 java 很好,我不仅说 go 是钻木取火,java ,rust 也是。连无穷整型都不是 builtin 的,都是比胶水 python 低一个层次的抽象。
性能和开发效率的极致得占一个吧~而不是像 go |
40
echoless OP @zagfai #39 现在这些语言就是 features 取舍的组合, go 我觉得就是宣传过头, 做一些 infra 的工具还行. 大公司做一些高并发啥的也可以理解, 小公司跟风上 go 去写 crud 感觉是无法理解的(动不动 BAT 谁谁都用了, nnd 是处理一样的问题么).
|
41
echoless OP 哪天 chatgpt, copilot 能写代码的时候, 估计又有高级程序员跳出来说, xxx 圈养了一堆 crud 都不懂, 只会 prompt 的 XX.
|