我眼中的编程语言 Rust 和 GO
| 2015-09-02 09:13 评论: 2
我已经花了不少时间在把玩一些新语言 – 特别要指出,Rust抓住了我的想象力。我们在Chef中使用大量的Ruby、Erlang和JavaScript(后来是Angular)代码。以下是我喜欢这些语言的东西:
- Ruby的感觉就像永远在敲打我头脑中“whipuptitude”部分。它很容易,可以简单的坐下来开始编码,你基本不会碰到困难。它也有类似Perl中我很喜欢的表达力。你越熟练这个语言,你就会越觉得你好像可以用英语(母语)表达自己的想法。
- Erlang和OTP极好操作。那些模式匹配、Actor并发、单一赋值,还有令人愉快的运行时导致运行、管理、调试产品服务是一种乐趣,我认为它语法是丑陋的,但是当你掌握它后,你会发现它的某种简洁美。
- 现代JavaScript以它自己的方式变得越来越讨人喜欢。比如你很容易就可以获取社区贡献的各种包和框架,像Angular那样纯粹的表现力,以及语言的经常使用部分的渐进式减肥都使体验变得愉快。过去我不喜欢它。
所以 – 我决定写一些Rust,还有Go,因为在我的世界里,每个人似乎看起来对它都很着迷。
Rust
我几个月前开始注意到Rust。这个语言被设计用来取代C/C++,适合进行底层开发,带有高的安全性保障和革新性的内存管理方式(borrowing借用)。它还有我喜欢的和Erlang蛮类似的语言特性:模式匹配、Actor样式并发,缺省不可变变量。
我使用C/C++的历史并不多。诚实的讲,我的强类型语言的编程经验并不多。作为一个系统管理员,我们通常就是给某人的程序打补丁(我做了很多这种事,但打补丁不像从头开发东西)。在我拥有的有限经验中,我发现编译->运行->排错循环太令人恼火。我承认这是我个人的无知:如果我多花时间来理解语言,我一定可以发现发现那些定期打击我的陷阱。
因此,我开始用Rust重写一个Ruby开发的命令行工具。我无意推销或者分享,它仅仅是我学习语言的一个借口(动力)。以下是我观察到的:
Cargo包管理器非常好
Cargo是负责Rust项目管理的一个非常好的前端工具。创建一个新的Rust项目,添加测试、依赖等等都非常的容易和简洁。
像脚本语言一样富有表现力
Rust就像一种非常富有表达力的底层脚本语言。更多请看下面这个链接:
https://gist.github.com/adamhjk/e296257b32818ee8691d.js
有些东西像as_slice()和Vec也许需要一点时间来解释,但它非常的直白。下面链接可以回顾这些函数:
https://gist.github.com/adamhjk/ead9de51d6f6d3aefeb2#file-review-rs
再次,我不认为写Rus会比写一种脚本语言更难。这需要一点时间来适应事实,比如,我从have_dot_git(cwd)返回一个选项Option,并且用模式匹配来抽取值(或者抛出错误)-但当你意识到引擎下面发生什么事情后,你就会觉得这很棒。
Strongly typed 强类型
在所有的强类型语言中,我总是觉得我和编译器在进行摔跤比赛。我发现很难信任编译器,与其说它可以阻止我做一些傻事,还不如说它没有理解我的方式。(我承认这是我自己的一种情感缺陷)Rust因以下这三个原因让人觉得不同:
- 它的编译错误信息非常的清楚,直接指出哪里错了,还经常给你提供精准的解决方案(“你是不是想…”)。
- 编译循环非常快,当我的代码成功编译后,它总是按我的想法准确的运行。
- 借用、使用期等概念需要点时间来习惯。但是,编译器确实每次都代表你的利益,再次,错误提示信息和规则是明确的。Rust没有传统的垃圾收集器-但它有非常清晰的规则来指示在栈和堆上的东西该活多久。这些规则和区域结合的很紧,在某种程度上,感觉很自然。
对于我最重要的是,我的代码从来没有segfaulted或者恐慌。这些都是我以前用底层系统编程语言中从来没有拥有过的体验。如果编译器接受我的输入,它开始运行-快速并且准确。
Rust有些库还不存在
Rust还在进化,快到1.0了(译者:现在1.2都出来了)。作为一个副作用,许多高级库都还不存在,或者还没被写出来。一个好的(小)例子是命令行语法解析库还不存在。有一个包包含在标准库里,但是界面效果不佳。Github中有一些有希望的库,但是最好的那个(从接口、功能性等来看)没有办法用最新的Rust来编译通过。(这是由于fail!(..)宏被改为panic!(..)-不是一件大事,但也是一件说明Rust还在演进的事实。)
同样,Cargo可以很好的获取依赖-但没有说明那些包可以获取,就像NPM、Rubygems或者CPAN那样。
关于Rust的最终想法
Rust是强大的,高度深思熟虑的系统编程语言,带有一些很好的、很有用的特性。(泛型、特质、模式匹配、Actor并发、借用-不胜枚举)。 那需要一下税负来学习并用“Rust方法”来解决问题-语言本身是简单的,但需要和一些不同的概念较劲。(译者:如果你了解函数式编程Scala, Haskell,就会觉得学习Rust很快)
也就是说,我第一次觉得自己可以相信自己可以快速写出一个快速、高效的底层系统代码。编译器非常友好,它提供的错误提示非常有用和清晰。当它演进到1.0,并且库的生态系统开始升温时-Rust将是一股不可忽视的力量。
Go
很多人说了很多关于Go如何神奇的事情。当我花了几个小时用Go重构一些东西后,我明白了这个诉求。
Go比较小巧
如果你有一些C衍生语言的编程经验,那么你可以很快的学会这门语言的一些表面领域。有很多东西你已经知道如何在语言中使用了:if/then /else,switch,for。它们的使用语法你已经知道了。它提供一些速记语法来简化一些类型冗长的打字工作。(比如 :=)。
Go是自以为是的 – 关乎很多事情
当你读“ 怎么编写Go代码”时,它就开始告诉你怎样从顶层源代码目录开始的每件东西你该怎么用Go写。Go的工具链知道怎样取得结构和做正确的事情-编译二进制到你的’bin’目录,运行你的测试,捕获依赖。
静态输出是好的-和现实,任何你本地编译的都会是你用户所消费的,感觉不错。
Go避免你的方法
Rust编译器让你很确定你的想法会如何在底层代码中工作,Go坐在中间。语言是强类型的,但在实践中,它大部分时间都似乎可以推断出你的意图。举例:
https://gist.github.com/adamhjk/5a475b8dd45971a4e814#file-dot_git_dir-go
在函数中唯一的类型注释是输入和输出-其他的每件事就是工作。感觉快速、容易、平易近人和非常少的麻烦。
Go的运行时失败
Rust运行时非常非常难出错。编译器让我确信我检查了每一个代码路径,总是确保我覆盖了每个角落。Go很乐意做我告诉它的东西 – 虽然编译器会阻止我的愚蠢,但它不会阻止我做这样的事:
https://gist.github.com/adamhjk/9c7eae1d053a1788f581#file-panic-go
在第九行盲目的假设正表达式找到匹配,然后导致运行时错误信息。这在Rust中绝不会发生。
https://gist.github.com/adamhjk/2eb74d326242a9093f9e#file-current_branch-rs
因为regex捕获的返回类型是Option选项,编译器知道我需要处理所有可能的值。我真的不能选择忽略它。这在我写代码的时候就发生了-在Go 中,我只写了我认为我想要的,然后在运行时才了解哪里错了(这是个很小的fix)。在Rust中,编译器在我第一次尝试这个函数时告诉我,我还没有对 Option返回值处理None结果。
速度,可访问性,还有库
权衡是有趣的。Go代码用更少的时间来写,语言容易访问,生态系统强大。它让我感觉在用脚本语言在工作,但同时避免了大多数恶名昭著的错误。因为唯一的语言结构是最常见结构,在语言中感觉很浅显,根本没有时间。
Go有巨大的库生态系统,一个清晰的方式来寻找它们,和一个简单的方式来得到它们。
所以...Rust还是Go?
我想,务实的回答是‘物尽其善,那个实用用哪个’。Go可以替代人们用Ruby、Pythong或者Perl所写的东西。它是一个简单,平易近人的语言,加上强类型和难以置信的生态系统。我明白人们为什么喜欢它。静态二进制,很好的生态系统,配合的很好。我写Go代码大概比Rust快一倍。
但是,我更喜欢Rust。我喜欢它有模式匹配、泛型、缺省的不可变数据。我喜欢如果我的代码编译通过,程序按我设计的意愿运行的可能性是极高的。当我想象一个生态系统将在这样的一个基础上建立出来时,我愿意活在那个世界里。这比我依赖大量语言用例,并且让我没有真正感觉到舒适的空间的世界要好。我很确定如果你用C/C++的话,Rust将非常吸引你。而你用Ruby或Python的话Go对你更有吸引力。然而,我想一旦Rusts生态系统起飞,它将同时吸引那些使用Ruby/Python的人。
我想起了一次高层招聘规则获取的教训,规则之一是他/她必须在某些方面让人惊讶一个在很多方面“好”的人,通常来说不是伟大的。Go就是给我这种感觉-它在每一方面都好,但没有抓住我的心,没有让我觉得因为在我已有的生态系统里面没有这些东西而觉得非常兴奋,Rust绝对惊人的保证你写的代码是在运行时正确和安全的-这是一种启示。
你一定要两者同时试一下。