大家好,我是煎鱼。
在六一儿童节前夕在摸煎鱼时,看到一个很神奇的 Go2 的技术提案,想要加一个更简略、更轻量的匿名函数语法。
明天就由煎鱼和大家一起看看。
新提案
新的 Go 提案目标是增加轻量级的匿名函数语法,业内别名又叫 “箭头语法”,是由 @Damien Neil 所提出的,提案的起源是《proposal: Go 2: Lightweight anonymous function syntax》,褒贬都有:
咱们由此进行开展。
如下例子:
<code class="go">import ( "fmt" "math" ) func compute(fn func(float64, float64) float64) float64 { return fn(3, 4) } func main() { hypot := func(x, y float64) float64 { return math.Sqrt(x*x + y*y) } fmt.Println(hypot(5, 12)) fmt.Println(compute(hypot)) fmt.Println(compute(math.Pow)) }
上述代码次要是实现了多个匿名的闭包函数,实际上业务逻辑没有什么。认为因为闭包签名繁冗,导致代码可读性不高。
为了防止这种状况,许多语言容许省略匿名函数的参数和返回类型,因为它们可能是从上下文派生的,可能间接被复用。
如下 Scala 的例子:
<code class="scala">compute((x: Double, y: Double) => x + y) compute((x, y) => x + y) // Parameter types elided. compute(_ + _) // Or even shorter.
Rust 的例子:
<code class="rust">compute(|x: f64, y: f64| -> f64 { x + y }) compute(|x, y| { x + y }) // Parameter and return types elided.
因而这个 Go 提案就是心愿针对匿名闭包减少这个轻量级的语法,让代码看起来更加的简洁,让代码可读性进步。
PHP 的例子:
<code class="php">$x = 1; $fn = fn() => $x++; // 不会影响 x 的值 $fn(); var_export($x); // 输入 1
更有那味了。
实在案例
Cap’n Proto
Go 开源库 Cap’n Proto(capnproto/go-capnproto2)是一种极其疾速的数据交换格局,相似于Protocol Buffers,但速度快得多。
以下是其代码应用片段:
<code class="go">s.Write(ctx, func(p hashes.Hash_write_Params) error { err := p.SetData([]byte("Hello, ")) return err })
假如咱们是 Rust,成果如下::
<code class="rust">s.Write(ctx, |p| { err := p.SetData([]byte("Hello, ")) return err })
errgroup
这个 errgroup 库置信大家不会生疏,罕用于多个 goroutine 的异步场景中的 err 解决和同步。
以下是其应用片段:
<code class="go">g.Go(func() error { // perform work return nil })
假如咱们是 Scala,成果如下:
<code class="scala">g.Go(() => { // perform work return nil })
只从代码数量来比照看,的确是简洁一些。
探讨
这个提案引起了社区不小的轰动和探讨,有多种不同的观点。
语法格局
先从 Go 的语法角度来看。语法格局为:
[ Identifier ] | "(" IdentifierList ")" "=>" ExpressionList
例子会变成:
<code class="go">s.Write(ctx, p => p.SetData([]byte("Hello, ")) g.Go(=> nil)
更更更短了。
升高了可读性
许多小伙伴认为这反而升高了代码可读性,更难懂了,还得在脑子里转换几道,能力晓得是什么意思…
你想想,轻易在公司上抓一只煎鱼。假如他没有提前理解过这个语法,他能读得懂这段代码是什么意思吗?
如下:
<code class="go">g.Go(=> nil)
显然,他没法 100% 确定。但没有这语法时,只是失常的匿名闭包,是能够读懂的。因为语法根本是通识,而箭头语法并不是。
晚期设计被回绝
在 Go 晚期的设计,其实对 “箭头语法”,也就是本提案进行过钻研。
过后的语法是:
<code class="go">func f (x int) -> float32
因为它不能很好地解决多个(非元组)返回值; 一旦呈现 func 和参数,箭头就多余了,会变得很简单。
尽管这么做会看起来更 “丑陋”,但 “丑陋”(就像在数学上看起来一样)可能依然是是多余的。它看起来也像是属于一种“不同”语言的语法。
官网也认为必须十分小心,不要为闭包创立非凡语法。因为当初 Go 所领有的是简略而法则的语法和逻辑。
最终放弃了增加箭头语法的想法。
用省略符代替
从代码示例来看,引起繁冗的次要是类型申明和构造。因而也有人提出应用省略符来实现相似成果。
如下代码:
<code class="go">s.Write(ctx, func(p _) _ { return p.SetData([]byte("Hello, ")) })
这样的益处是不须要语法扭转。
总结
原提案作者的本意,可能是须要让匿名闭包更加的简洁,升高代码复杂度。但其实这实质上,节约的只是明面上的复杂度。
一旦引入这类 “箭头” 语法,可能会更大的加剧脑子转换的开销。看代码时,得想想对对,会减轻底下的脑力开销。
当然,说不定我也是错的。你感觉呢?是否反对 Go 新增轻量级的匿名闭包语法,也就是业内俗称的 “箭头” 语法。
欢送大家在评论区留言和交换。
文章继续更新,能够微信搜【脑子进煎鱼了】浏览,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言能够看 Go 学习地图和路线,欢送 Star 催更。
Go 图书系列
- Go 语言入门系列:初探 Go 我的项目实战
- Go 语言编程之旅:深刻用 Go 做我的项目
- Go 语言设计哲学:理解 Go 的为什么和设计思考
- Go 语言进阶之旅:进一步深刻 Go 源码