// 这是一段 swift 代码
var hello = [10, 20, 30, 40, 50, 60]
var foo = hello[2..<5] // 表示索引范围是 2 ,3 ,4
foo[2] = 0
print(foo)
// 先看看你的程序员直觉,输出结果是什么
然后随便 google 找个 swift playground 运行这段代码,你就知道为什么苹果现在 bug 越来越多了。
1
ourstars 15 小时 53 分钟前 直觉理解是[30,40,0],但是运行之后是[0,40,50]。
foo 用的是 hello 的索引范围造成了[0,40,50]的结果。 |
3
TianDogK48 14 小时 28 分钟前 via iPhone 目测这个语法不常用,所以问题应该不大; go 里面 slice 扩容,也有坑,但是目测 go 的 slice 很少用,都是直接 make
|
4
raycool 14 小时 26 分钟前
看来都是 slice 的不同理解导致的。
|
5
smlcgx 14 小时 23 分钟前 via iPhone
这样看起来 swift 更偏向自然语言一点,几就是几
|
6
butanediol2d 13 小时 45 分钟前
hello 是 Array<Int>
foo 是 ArraySlice<Int> |
7
craftsmanship 13 小时 32 分钟前 via Android
如此说来 JS 早先那些垃圾设计可能导致的 bug 只会更多。。
|
8
xuejianxianzun 11 小时 54 分钟前
@craftsmanship 怎么又扯到 js 了,js 在这个场景里没有反直觉的行为。
|
9
hash 8 小时 13 分钟前 系统层核心实现是一坨屎,与语言设计无关
|
10
Building 7 小时 14 分钟前
都按直觉那不同语言反人类的语法简直不要太多,当然不影响 Swift String 的设计才是最为逆天的东西
|
11
cpstar 6 小时 35 分钟前
@xuejianxianzun 8# 以我不动 swift ,和 1#的情况,我觉得基本上就是 js 的逻辑:
foo_js[2]=hello[2]/*30*/,foo_js[3]=hello[3]/*40*/,foo_js[4]=hello[4]/*50*/ 而 foo_js[0]=undefined,foo_js[1]=undefined 于是 foo_js[2]=0 之后,foo_js={"2":0,"3":40,"4":50} |
12
Greendays 6 小时 31 分钟前 和语言关系不大的,既然做了开发掌握这个语言的语法是基本要求。Bug 多只是需求超过了能力,不得不赶工和减少测试流程造成的。
|
13
Lin0936 6 小时 23 分钟前
再逆天的语言也该经过测试啊
|
14
june4 6 小时 20 分钟前
@craftsmanship js 真没有啥绕不过去的垃圾设计,特别是 ts 上身后,底子非常干净纯洁,现在只有一个日常使用我觉得不爽,就是搞出二个 null/undefined 类型。
|
15
xiangyuecn 6 小时 12 分钟前
苹果拉的屎就是香,没啥毛病 能咽下去的
|
16
freeloop1 6 小时 1 分钟前
那个 foreach 的语法我是最蚌埠住的,我总感觉是少写了括号啥的,太难受了。
|
17
a33291 5 小时 56 分钟前
foo 是 hello 的视图吧? 现在很多语言/库都提供这种东西,减少 copy,不过大部分是只读的比较合理
|
19
fadaixiaohai 5 小时 37 分钟前
从 swift6 开始越来越复杂,关键词越搞越多,问题是有些关键词编译器都支持不太好,搞不好就容易 crash ,对新人也不太友好
|
20
PlG5sBkXD1ziLeGB 5 小时 33 分钟前 via iPhone
swift 的语法真是丑到爆,OC 的语法虽然跟裹脚布一样长,但是可读性非常强
|
21
deplives 5 小时 30 分钟前
|
22
kfpenn 5 小时 28 分钟前
@PlG5sBkXD1ziLeGB 赞同
|
23
liuhan907 5 小时 15 分钟前 这个输出 [0, 40, 50] 不才是符合直觉的?
|
24
cpper 5 小时 12 分钟前
每个语言有每个语言的用法,不要陷入奇巧淫技的细节中
|
25
liuhan907 5 小时 7 分钟前 哦,大意了,foo[2] 啊。那这是傻逼设计,我看的不够仔细啊 -_-
|
26
IDAEngine 5 小时 5 分钟前
这是一个关于 Swift 数组切片( Array Slice )行为的有趣问题。
我的“程序员直觉”告诉我,输出结果是: [0, 40, 50] 解释(为什么我的直觉是这样): 切片操作: var hello = [10, 20, 30, 40, 50, 60] var foo = hello[2..<5] 创建了一个数组切片( Array Slice )。这个切片包含 hello 中索引 2,3,4 的元素。 foo 此时是 [30, 40, 50]。 关键点:数组切片的索引继承了原数组的索引。所以 foo 内部元素的索引是 2,3,4 ,而不是从 0 开始。 修改切片: foo[2] = 0 尝试修改 foo 中索引为 2 的元素。 在 foo 中,索引 2 对应的值是 30 。 修改后,foo 变成了 [0, 40, 50](注意,尽管内部值变了,它的索引结构仍然是 2,3,4 )。 打印切片: print(foo) 打印切片的内容。Swift 在打印数组切片时,会打印其包含的元素值。 因此,输出是 [0, 40, 50]。 |
29
yuanxing008 4 小时 57 分钟前
可能 go 和 python 写的太久了 我的第一直觉就是[0,40,50]
后面看你们讨论才发现这个设计很扯,但是写习惯了就好了😁 |
30
2en 4 小时 55 分钟前
居然不是 30,40,0
|
31
leeg810312 4 小时 51 分钟前
@IDAEngine 你的直觉才有问题。无论是创建新数组,还是视图,都不该是这样的行为。按业务逻辑,这段代码描述应该是这样,从 A 数组中取第 2-4 (从 0 开始)的元素,作为 B 数组,B 数组的第 2 个元素值改为 0 。关键点,B 的第 2 个元素,实际行为却去改 A 的第 2 个,这完全是反直觉的,即使 B 是视图,非实际创建的新数组,也应当把 B 当作一个逻辑上独立的数组去使用。
|
32
PlG5sBkXD1ziLeGB 4 小时 49 分钟前 via iPhone
@yuanxing008 啊?你用过 go 的 slice 吗兄弟,还是你把 `foo[2] = 0` 看成 `hello[2] = 0`了
|
33
cpstar 4 小时 47 分钟前
@november 27# 如果是 js ,那会生成一个新的副本,foo_js 是{"0":30,"1":40,"2":50},然而按照 21#,更像是 foo 就是 hello ,修改了 foo 一并修改 hello ,只不过限定了 foo 的游标只有 2 、3 、4 取值,如果 foo[1]是不是要报错。
|
34
ripperdev 4 小时 46 分钟前
@yuanxing008 go 不是这样啊,输出肯定是[30 40 0]
|
35
superrichman 4 小时 45 分钟前 @yuanxing008 #28 你这 python 没学好啊 🐶 python 里面是 [30, 40, 0]
一行命令跑出来就知道了 python -c "a=[10,20,30,40,50,60];b=a[2:5];b[2]=0;print(b)" |
36
guanhui07 4 小时 44 分钟前
之前我也学了下 swift 的语法..
|
37
leeg810312 4 小时 43 分钟前
@yuanxing008 你的直觉错了。go 我不知道,python 的切片是创建一个新 list
a = [0, 2, 4, 6, 8, 10] b = a[2:5] b[0] = 3 b[2] = 9 print(a) print(b) 输出: [0, 2, 4, 6, 8, 10] [3, 6, 9] |
38
wangkun2012324 4 小时 41 分钟前 正确的用法永远是使用 startIndex 和 offset/advanced
``` var hello = [10, 20, 30, 40, 50, 60] var foo = hello[2..<5] // 表示索引范围是 2 ,3 ,4 foo[foo.startIndex.advanced(by: 2)] = 0 print(foo) // [30, 40, 0] ``` |
39
junj2121 4 小时 40 分钟前
C 出生的人 一看就知道结果啊。
这种赋值逻辑肯定是从指针赋值上考虑。 都觉得 C 垃圾,其实并不然 |
40
noErr 4 小时 39 分钟前
js 仔采用 switft
|
41
Torpedo 4 小时 36 分钟前
@june4 #14 这两个可以不分的。主流库里,常见的只有 react 组件的返回和 json 严格区分了这两个。js 判断 null 和 undefined 如果不分,直接用 a!=null 判断就行了
|
42
idonttellyou 4 小时 32 分钟前
为什么不是[30, 40, 0]呢...
|
43
V2Try 4 小时 29 分钟前 via iPhone
这个确实奇怪,如果
foo[2] = 0 换成 hello[2] = 0 结果是不是一样的? |
44
Wanex 4 小时 28 分钟前
先别管 swift 符不符合直觉,也别管 js 有没有同样的问题,总之先骂 js 再说🤣
|
45
november 4 小时 26 分钟前 via iPhone
@cpstar 其实 #27 的答案是 ai 结果,实际运行结果是 hello 没变。
所以更验证了楼主说的“一堆 ai 回答错”。233333 |
46
ChrisFreeMan 4 小时 26 分钟前
@idonttellyou 因为很多人理所当然的认为 foo 是拷贝了一个新的数组,实际上 foo[2]指向了原来的数组,foo 只是引用了愿数组 hello 。
|
48
PlG5sBkXD1ziLeGB 4 小时 21 分钟前
|
49
Huelse 4 小时 21 分钟前
确实反直觉
|
50
beimenjun PRO 这个并不是苹果现在 bug 越来越多的原因。
我还以为是讲技术债之类的,结果居然是吐槽 Swift 的语法。真的是浪费时间。 |
51
ChrisFreeMan 4 小时 20 分钟前
@idonttellyou 好吧,我搞错了,自己试了下,原数组并没有改变值
|
52
ChrisFreeMan 4 小时 20 分钟前
@PlG5sBkXD1ziLeGB 我刚刚试了下确实是,没有改变,我收回我的傻逼言论
|
53
lihanst 4 小时 18 分钟前
看到这种结果,应该思考为什么要设计一个 ArraySlice ?目的是什么?代价是什么?
|
54
VXF2016 4 小时 18 分钟前
真离谱
|
55
caiqichang 4 小时 18 分钟前
|
56
usVexMownCzar 4 小时 18 分钟前 via iPhone
没啥好吵的,swift 的 Array 并不是传统概念的数组,真正的数组(连续存储)是最近版本才添加的,InlineArray 。
话说目前还没看到从源代码来分析上面的代码为什么这么设计🌚 |
57
mizuki9 4 小时 7 分钟前
好奇葩的设计,好奇葩的行为
|
58
luodan 4 小时 3 分钟前
学习了。以后遇到 slice 多留意点。
|
59
FlashEcho 4 小时 1 分钟前
@junj2121 #39 c 根本就没有数组切片,得自己手写,天然就会知道这个是一个视图还是拷贝出来一个新的,不参与讨论。c++的数组拷贝是默认拷贝出来一个新的
|
60
whitefable 3 小时 53 分钟前
@junj2121 #39 即使是 C 出身也很反直觉好吧。 要说从指针赋值上去考虑,那 foo 不应该也是指向了 hello[2]么,那此时 foo[2]也是对应 hello[4]才对
|
61
beimenjun PRO @usVexMownCzar
苹果关于 ArraySlice 的文档( https://developer.apple.com/documentation/swift/arrayslice )原话是这么说的“Sharing indices between collections and their subsequences is an important part of the design of Swift’s collection algorithms.” 除了 Array 和 ArraySlice ,甚至 String 和 Substring ,Data 和 Data.SubSequence 都是这样子的。 感觉最直观的好处就是可以在原对象和切片之间需要频繁调整 index 的步骤简化掉这一步骤。 比如 Apple 的示例: ``` let absences = [0, 2, 0, 4, 0, 3, 1, 0] if let i = absences.firstIndex(where: { $0 > 0 }) { // 1 let absencesAfterFirst = absences[(i + 1)...] // 2 if let j = absencesAfterFirst.firstIndex(where: { $0 > 0 }) { // 3 print("The first day with absences had \(absences[i]).") // 4 print("The second day with absences had \(absences[j]).") } } // Prints "The first day with absences had 2." // Prints "The second day with absences had 4." ``` |
62
xz410236056 3 小时 30 分钟前
@ourstars
@qdwang 因为你们没看文档,foo 并不是个 array ,而是一个切片(ArraySlice),他的索引并不从 0 开始(取决于你创建方式,大多数共享)。你需要使用特定的函数达到 array 的效果。 https://developer.apple.com/documentation/swift/arrayslice |
63
xz410236056 3 小时 30 分钟前
@fadaixiaohai 关键词现在能搞本书了,恶心的要死。人类根本记不全
|
64
Leeeeex PRO |
65
ikw 2 小时 52 分钟前
@PlG5sBkXD1ziLeGB #48 前面保留 index 我都能认为是语言的特性,找到对应的文档并且接受了,但是不修改原数组我就懵了。
Slice 作为保留原 index 的轻量化视图,修改操作不影响原数组,那修改部分去哪里了?总不能是 Copy on Write 新建了一个 Array 吧,而且这么奇怪的逻辑没有文档强调? https://developer.apple.com/documentation/swift/arrayslice |
66
qdwang OP @wangkun2012324 老哥厉害👍
|
67
coudey 2 小时 41 分钟前
有够奇葩的,普通 gpt5 也搞错了。hello 被修改能理解,foo[2]用 hello 的索引真是逆大天
|
68
sankemao 2 小时 20 分钟前
太奇葩了,就你 swift 要搞特殊
|
69
butanediol2d 2 小时 7 分钟前
@PlG5sBkXD1ziLeGB COW 生效了,在修改之前,底层使用的 array 是同一块内存,修改时 foo 进行了复制,不是同一块内存了
|
70
yolee599 1 小时 29 分钟前 via Android
|
71
wangkun2012324 1 小时 17 分钟前
swift 的数组,包括之前吐槽的 string, 一切源于 collection 的设计,collection 的 startIndex 和 endIndex, swift 一致期望用户不使用整数索引,你查看数组的一些排序算法等你会发现根本不是数组的方法,而是 collection 甚至别的 sequence 的各种方法,并且不是所有。
设计者在做通用的 collection 算法时,https://forums.swift.org/t/rant-indexing-into-arrayslice/14105/14 决定了 Array Slice 这么做。其实我认为这么做之后,array[1]这种风格的写法, 只是 swift 数组只是恰好对的写法,因为 Array.Index 是 Int 。string[1]就不对了。吐槽也是合理的。毕竟是常见的语法,违反直觉的语义 |
72
Azone 1 小时 15 分钟前
@PlG5sBkXD1ziLeGB foo[2] 指向的是元素组的索引,不是指向的是原数组。Swift 所有的值类型都是 COW 技术,当你把一个变量赋值给另一个变量并且改变它的值的时候,他们指向的就不是同一块内存了。
|
73
laikicka 1 小时 7 分钟前
@craftsmanship js 的 bug 还少吗
|
74
decken 54 分钟前
语法问题导致的 bug 应该极少吧
|
75
clarkethan 25 分钟前
想了一下,有可能是出于性能考虑吧,减少不必要的深拷贝和内存分配
再深入想一想,如果我是经常使用 swift 的人,这个设计好像又是可以接受的,语法上这种写法就相当于是一种借用切片,语以上只是记录一下借用范围而已。如果需要在 var foo 的时候直接深拷贝内容,直接用 Array 构造一个新的数据,应该是语言推荐的做法吧。如果有以上心智在前,好像倒不会有太多问题了,不少场合确实能节约一些性能,尤其是资源能耗敏感的场景 我实际上不写 swift ,仅猜测 |
76
ikw 13 分钟前
@butanediol2d #69 这样的话,又有几个问题,
既然设计了 CoW ,那 foo 预期是会作为独立对象存在的,为什么还要用原数组的索引呢? CoW 是复制整个 Array 还是复制 slice 对应部分呢? foo 有了自己的内存,按说讲他和 hello 已经没什么关系了,这个时候 foo 还要一直用 hello 的索引,似乎也很奇怪吧? |
77
tiancaixiaoshuai 4 分钟前
直觉是重置索引,我没学过 swift ,如果这是语言特性,也能接受,就像 php 也可以使用 array_slice()里面的 preserve_keys 设为 true 保留原索引,并且这个跟 bug 多也没什么关系吧
|