go 新特性 range over func 没怎么看懂。。。。写库的时候用吗?

306 天前
 dyllen

go1.23 新的正式特性 range over func 看了下没怎么看懂。。。

for range 返回一个函数,函数里面还是 for range 或者就 for 循环:

func Backward[E any](s []E) func(func(int, E) bool) {
    return func(yield func(int, E) bool) {
        for i := len(s) - 1; i >= 0; i-- {
            if !yield(i, s[i]) {
                return
            }
        }
        return
    }
}

func main() {
    sl := []string{"hello", "world", "golang"}
    for i, s := range Backward(sl) {
        fmt.Printf("%d : %s\n", i, s)
    }
}

Backward这个函数这形式看起来还真有点复杂,不好理解。。。。可能例子不是相应场景下需要的,看半天没理解。 感觉一般都用不上。

11711 次点击
所在节点    Go 编程语言
105 条回复
Elaina
306 天前
@cmdOptionKana 我没说不能加泛型啊,写 parser 别偷懒用方括号啊
EAFA0
306 天前
``` golang
EAFA0
306 天前
研究了一下... 你把这块代码这样看:

``` golang
func Backward[E any](s []E) func(func(int, E) bool) {
return func(yield func(int, E) bool) {
for i := len(s) - 1; i >= 0; i-- {
if !yield(i, s[i]) {
return
}
}
return
}
}

func main() {
sl := []string{"hello", "world", "golang"}

iter := Backward(sl)

iter(func(index, value) bool {
fmt.Printf("%d : %s\n", i, s)
return true
})
}
```

是等效的, 不知道这个能不能帮助你理解, 实际上这个新特性看起来只是加了个编译时替换 (可能描述的不准确)
cmdOptionKana
306 天前
@Elaina

你说“越来越依托答辩”、不简洁、“代码搞得又臭又长”、“现在又开始整活”

结果你真正想表达的却是“不喜欢方括号”。你一开始的原话与你最终的表达相差太大了。
laikick
306 天前
@cmdOptionKana 不管怎么说. range over func 确实感觉破坏了 golang 代码易读这个优点
Elaina
306 天前
@cmdOptionKana 这几点不冲突啊,我不喜欢方括号是因为可读性差啊,parser 又不是不能处理尖括号,所以我说它是依托答辩啊,你要搞就好好搞呗,搞了但又搞成依托答辩,以及不简洁不代表代码会又臭又长,简洁了不代表可读性就好
QXDM
306 天前
@cmdOptionKana #28 能清晰的看到依托 shit 的组成与产出
cmdOptionKana
306 天前
@laikick 这是个很普通的特性,也很直白,觉得不易读大概率是之前类似的写法看得比较少,不习惯而已。
cmdOptionKana
306 天前
@QXDM

A. 能看清 shit 的产生过程
B. 看不清过程,反正产生 shit

作为写代码解决问题的人,你认为哪个好?
cmdOptionKana
306 天前
@Elaina 你这一段很混乱,我理不清其中的逻辑,因此无法反驳。
vfs
306 天前
@cmdOptionKana 如果一开始 golang 就支持了泛型, 我可能根本不会去学它, 因为我完全可以去学习更牛逼的 Java 。 我之所以喜欢他, 是因为它有着像 c 一样简单的语法。 如今 golang 只是在慢慢的编程另外一个 java 而已, 而这个世界根本不需要另外一个 java 语言。这也就是为为什么对它支持泛型不太看好。今天能支持泛型, 明天就能支持异常。
cmdOptionKana
306 天前
@vfs golang 从来没有承诺不添加泛型。事实上在没有泛型的时候,确实有很多人不得不用 interface 来模拟泛型,这个需求是真实存在的。添加泛型后,社区文化也是尽量控制泛型的使用范围,能不用就不用,只在有明显帮助的时候才用。就目前来看还是比较乐观的,泛型不会蔓延得太厉害。
0x67cq
306 天前
@EAFA0 嗯,看你这个例子就感觉比较好理解,最上面那个很难理解的点在于 range 本身是一个语法糖。我没办法直接看出来,它构造了一个什么 yield 函数作为参数传入 Backword 执行后返回的结果函数用于执行。你这里把 `for k,v := range iter` 改写成 `iter ( func()bool{} return true)`这种方式就很明确。相当于把语法糖解开了。总的来说我不喜欢这个语法糖。
0x67cq
306 天前
@EAFA0 我读上面最开始卡到的地方其实就是,for k,v := range iter{fmt.Printf...} 这里,我无法理解 生成的 iter 是怎么得到 yield 这个参数函数的。简单来说就是,TMd 的哪来的 yield 。
victorc
306 天前
谁 tm 提的,这人是个纯 SB

c++被弄成现在这个鸟样就是有这群鸟人把持标准委员会
kk2syc
306 天前
大伙要像果粉学习,自适应很重要!丑归丑,能用好用性能好就行了……
kingcanfish
306 天前
@0x67cq #74 而且 yield 返回值是个 bool 值 tmd 拿来的布尔值 tmd 到底怎么跳出迭代 晕了
vfs
306 天前
@cmdOptionKana "很多人不得不用 interface 来模拟泛型": 其实我并不觉得这是什么问题, 就像在 c 里面用 void* 来指向任何地址的做法一样。
EAFA0
306 天前
@0x67cq 我一开始也很奇怪, 搓了几段代码后发现这个 for range 跟 py 那种 yield 语法可以说是没有一点关联性... 这个语法糖远不如直接调用直观, 有一点关联性的是 iter 包下面的 Pull / Pull2 方法, 这两个方法的效果才跟其他语言的迭代器有点类似
MoYi123
306 天前
@Nazz 如果这个数据结构基于硬盘, 提供的接口是 async 的, 这种传入回调函数的方式可以大幅减少 await 的次数, 性能会比 await iter.next() 好很多.

虽然 go 里用不到这个.

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

https://ex.noerr.eu.org/t/1066038

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

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

© 2021 V2EX