Rust vs Go
译者按:其实我只学过Golang,Rust啥的在本文发出时根本不懂,错了别打我哈哈哈哈哈。 原文地址:https://bitfieldconsulting.com/golang/rust-vs-go
Which is better, Rust or Go? Which language should you choose for your next project, and why? How do the two compare in areas like performance, simplicity, safety, features, scale, and concurrency? What do they have in common, and where do they fundamentally differ? Let’s find out, in this friendly and even-handed comparison of Rust and Golang, from the author of the For the Love of Go book series.
Rust和Go哪个更好?为了你的下一个项目应该选择哪个语言,为哈?在性能,简便,安全,特性,规模和并发上这两种语言该如何比较?它们有什么地方相同又有什么本质上的不同?让我们从For the Love of Go系列书籍作者的这篇友好又不失公正的比较中找到答案吧。
Rust and Go are both awesome #
First, it’s really important to say that both Go and Rust are absolutely excellent programming languages. They’re modern, powerful, widely-adopted, and offer excellent performance. You may have read articles and blog posts aiming to convince you that Go is better than Rust, or vice versa. But that really makes no sense; every programming language represents a set of trade-offs. Each language is optimised for different things, so your choice of language should be determined by what suits you and the problems you want to solve with it.
In this article, I’ll try to give a brief overview of where I think Go is the ideal choice, and where I think Rust is a better alternative. Ideally, though, you should have a working familiarity with both languages. While they’re very different in syntax and style, both Rust and Go are first-class tools for building software. With that said, let’s take a closer look at the two languages.
Rust和Go都很棒 #
首先,很重要的一点是Go和Rust都是很不错的编程语言。它们都是现代,强力,广泛采用和提供绝佳性能的语言。你或许读过一些文章和博客帖子,试图说服你Go比Rust好多了,或者相反。但那一点道理也没有,每个编程语言都提供一些权衡取舍。每个编程语言都为不同的事物进行优化,所以你在语言上的选择应取决于是否适合你和你所想要解决的问题。
在这篇文章,哪里我觉得Go是理想选择,哪里我又觉得Rust是更好的替代项,关于这些我会尝试给出简短的综述。理想情况下你应当在工作的时候都对这些语言比较熟悉。即使它们在语法和风格上有着很大的不同,但Rust和Go都是创建软件的第一梯队工具。带着这些说法,让我们来拉近距离看看这两种语言。
The similarities #
Rust and Go have a lot in common, which is one reason you often hear them mentioned together. What are some of the common goals of both languages?
Rust is a low-level statically-typed multi-paradigm programming language that’s focused on safety and performance.
Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
—Golang.org
相似性 #
Rust和Go都有很多相同点,这也是你老是一起听到它们的原因之一。什么是这两种语言的共同目标?
Rust是一个底层,静态类型,多范式的编程语言,专注于安全和性能。
Go是一个开源的编程语言,它可以方便创建简单,可靠又高效的软件。
—Golang.org
Memory safety #
Both Go and Rust belong to the group of modern programming languages whose priority is memory safety. It’s become clear over many decades of using older languages such as C and C++ that one of the biggest causes of bugs and security vulnerabilities is accessing memory unsafely or incorrectly. Rust and Go deal with this problem in different ways, but both aim to be smarter and safer than other languages about managing memory, and to help you write correct and performant programs.
内存安全 #
Go和Rust都属于以内存安全作为优先考虑的现代编程语言。在使用较老的语言的这数十年中,比如C和C++,越来越清楚地发现造成bug和损害安全的最大起因之一是访问内存不安全或不当。Rust和Go用不同方式处理这个问题,但在管理内存上都比其他语言更为智能和安全,帮助你写出正确又高性能的程序。
Fast, compact executables #
They’re both compiled languages, which means your programs are translated directly to executable machine code, so that you can deploy your program as a single binary file; unlike interpreted languages such as Python and Ruby, you don’t need to distribute an interpreter and lots of libraries and dependencies along with your program, which is a big plus. This also makes both Rust and Go programs extremely fast in comparison to interpreted languages.
快速紧凑的可执行程序 #
它们都是编译型语言,意味着你的程序可以翻译为可执行机器码,所以你可以把你的程序部署为单独的二进制文件,而不用像解释型语言例如Python和Ruby那样需要分配一个解释器和一堆库和依赖,这是一个巨大的优势。这使得Rust和Go比起解释型语言更为快速。
General-purpose languages #
Rust and Go are also both powerful, scalable general-purpose programming languages, which you can use to develop all kinds of modern software, from web applications to distributed microservices, or from embedded microcontrollers to mobile apps. Both have excellent standard libraries and a thriving third-party ecosystem, as well as great commercial support and a large user base. They’ve both been around for many years, and will continue to be widely used for years to come. Learning either Go or Rust today will be a sound investment of your time and effort.
通用语言 #
Rust和Go都是强力和大规模通用型编程语言,你可以用它们开发各种现代软件,从网络应用到分布式微服务,或者从嵌入式微机控制器到移动应用。他们都有极佳的标准库和繁荣的第三方生态圈,同时也有不错的商业支持和巨大的用户基础。它们都被使用很多年,也会在接下来的数年中继续广泛应用。在今天学习Go和Rust是用你的时间和努力取得的不错的投资。
Pragmatic programming style #
Neither are primarily functional languages (like Scala or Elixir, for example), and neither are exclusively object-oriented (like Java and C#). Instead, while both Go and Rust have features associated with functional and object-oriented programming, they’re pragmatic languages aimed at solving problems in whatever way is most appropriate, rather than forcing you into a particular way of doing things. (If you like the functional style of programming, though, you’ll find a lot more facilities for it in Rust, because Rust has a lot more facilities than Go in general.)
We can debate about what an ‘object-oriented’ language is, but it’s fair to say that the style of object-oriented programming that C++, Java, or C# users would expect is not present in either Go or Rust.
—Jack Mott
实用主义编程风格 #
不是原教旨函数式语言(像Scala或Elixir)也非专门面向对象范式(例如Java和C#)。相反,Go和Rust都有着函数式和面向对象编程的特性,同时它们也是实用编程语言,致力于用最便宜的方式解决问题,而非逼你用某种特殊的方式。(如果你喜欢函数式风格编程,你还是能在Rust上找到很多关于此的机制,因为Rust比Go提供更多的一般功能。)
我们可以一直争论什么是“面向对象”语言,但可以说C++,Java或者C#的用户期望的那种面向编程风格不管在Go还是Rust都未出现。
—Jack Mott
Development at scale #
Both Rust and Go have some useful features which make them suitable for programming in the large, whether that means large teams, or large codebases, or both.
For example, whereas C programmers have argued for years about where to put their brackets, and whether code should be indented with tabs or spaces, both Rust and Go eliminate such issues completely by using a standard formatting tool (gofmt for Go, rustfmt for Rust) which rewrites your code automatically using the canonical style. It’s not that this particular style is so wonderful in itself: it’s the standardisation which Rust and Go programmers appreciate.
gofmt’s style is no one’s favourite, yet gofmt is everyone’s favourite.
Another area where both languages score highly is in the build pipeline. Both have excellent, built-in, high-performance standard build and dependency management tools; no more wrestling with complex third-party build systems and having to learn a new one every couple of years.
Building Go and Rust code, having come from a Java and Ruby background in my early career, felt like an impossible weight off my shoulders. When I was at Google, it was a relief to come across a service that was written in Go, because I knew it would be easy to build and run. This has also been true of Rust, though I’ve only worked on that at much smaller scale. I’m hoping that the days of infinitely configurable build systems are dead, and languages all ship with their own purpose-built build tools that just work out of the box.
大规模开发 #
Rust和Go都有着适合大规模编程的实用特性,不管是大型团队还是大型代码库或其他。
举个例子,C程序员在哪里放置他们的括号,还是代码应该要用制表键还是空格键缩进争论了不少年头,然而Rust和Go利用标准格式化工具(Go的gofmt,Rust的rustfmt)完全消除这些问题,使得你的代码可以用标准的风格自动重写。他本身的特定风格并不是如此美妙,Rust和Go程序员更欣赏它的标准化。
gofmt的风格并不是任何人的最爱,但gofmt本身是所有人的最爱。
另一个这两种语言得分很高的领域是编译流程。它们都有着绝佳,内建,高性能标准编译和依赖管理工具;再也不用和复杂的第三方编译系统较劲,而且学习一个新系统需要耗费数年。
编译Go和Rust代码,从我早年Java和Ruby的经历来看,感觉像从我的肩头上卸下不可能赶走的负担。当我在Google的时候,遇到一个用Go写的服务令人松了一口气,因为我知道它很容易编译和运行。对于Rust而言也是对的,尽管我只是在小得多的规模上用它工作过。我希望那些无穷无尽构建编译系统的日子不要再来,而且所有语言都应装箱在它们自带的专门编译工具然后再出箱工作。
So what’s all the fuss about? #
With all that in mind, and seeing that both languages are so well-designed and powerful, you might be wondering what all the holy wars are about (me too). Why do people make such a fuss about ‘Go versus Rust’, getting into angry social media spats and writing long blog posts about how only an idiot would use Rust, or that Go isn’t a real programming language, or whatever. It might make them feel better, but it doesn’t exactly help you, as someone trying to decide which language to use for your project, or which you should learn to advance your programming career. A wise person doesn’t make important choices based on who shouts the loudest.
Let’s continue our grown-up discussion now by looking at some areas where a reasonable person might prefer one language over the other.
所以有什么好大惊小怪的? #
记住这些在脑袋里,看过这些良好设计和强力的语言,你或许想知道那些语言圣战围绕什么发生的(我也是)。为什么人们对“Go大战Rust”如此过分关心,进行了愤怒的社交媒体口水战,而且写了冗长的博文来论证一个傻子如何使用Rust或者Go不是一个真正的编程语言,诸如此类。这让他们感觉良好,但它不会真地帮到你,如果你试图决定哪种语言应用到你的项目或者你该学些啥来精进你的编程之路。一个聪明人从不看谁嗓门大就做出关键决定。
让我们继续成年人之间的讨论,来看看一些领域中一个理性人为何偏爱一种语言。
Performance #
We’ve said that both Go and Rust produce extremely fast programs because they’re compiled to native machine code, without having to go through an interpreter or virtual machine. However, Rust’s performance is particularly outstanding. It’s comparable with C and C++, which are often regarded as the highest-performance compiled languages, but unlike these older languages, it also offers memory safety and concurrency safety at essentially no cost in execution speed. Rust also allows you to create complex abstractions without paying a performance penalty at run-time.
By comparison, although Go programs also perform extremely well, Go is primarily designed for speed of development (including compilation), rather than speed of execution. The Go compiler doesn’t spend a lot of time trying to generate the most efficient possible machine code; it cares more about compiling lots of code quickly. So Rust will usually beat Go in run-time benchmarks.
Rust’s run-time performance is also consistent and predictable, because it doesn’t use garbage collection. Go’s garbage collector is very efficient, and it’s optimised to make its stop-the-world pauses as short as possible (and getting shorter with every new Go release). But garbage collection inevitably introduces some unpredictability in the way programs behave, which can be a serious issue in some applications, such as embedded systems.
Because Rust aims to give the programmer complete control of the underlying hardware, it’s possible to optimise Rust programs to be pretty close to the maximum theoretical performance of the machine. This makes Rust an excellent choice for areas where speed of execution beats all other considerations, such as game programming, operating system kernels, web browser components, and real-time control systems.
性能 #
我们已经说过Go和Rust都能很快产出程序,因为它们都是编译成原生机器码,不需要经过解释器或者虚拟机。然而,Rust的性能更胜一筹。它可以与C和C++一战,而且它经常被视为高性能编译型语言,但不同于较老的语言,它提供了内存安全和并发安全并且在执行速度上基本没有损失。Rust也允许你创建复杂抽象,但不会在运行的时候付出性能代价。
相对而言,尽管Go程序也能表现得不错,但Go一开始是为了开发速度(包括编译)设计的,而不是执行速度。Go编译器不会在生成更高效的机器码上花费很多时间;它更关心快速编译大量代码。所以Rust在运行时基准测试上经常击败Go。
Rust的运行时性能也是一致且可预测的,因为它不使用垃圾回收机制。Go的垃圾回收器非常高效,而且它尽可能优化了stop-the-world的暂停时间(而且随着每一版Go的发布越来越短)。但垃圾回收机制不可避免会带来程序行为上的不可预测性,在一些应用上比如嵌入式系统会造成严重的问题。
因为Rust专注于给予程序员对于底层硬件的完全控制权,所以有可能把Rust程序优化到极其接近于机器最大理论性能。这使得在运行速度作为首要考量的地方Rust成为极其不错的选择,比如游戏编程,操作系统内核,网络浏览器组件和即时控制系统。
Simplicity #
It doesn’t matter how fast a programming language is if nobody can figure out how to use it. Go was deliberately conceived as a reaction against the ever-growing complexity of languages like C++; it has very little syntax, very few keywords, and, indeed, few features. This means it doesn’t take long to learn the Go language to the point where you can write useful programs in it.
Go is incredibly easy to learn. I know this is an often-touted benefit, but I was really surprised at how quickly I was able to be productive. Thanks to the language, docs, and tools, I was writing interesting, committable code after literally two days.
The key word here is simplicity. Simple isn’t the same as easy, for sure, but a small, simple language is easier to learn than a large, complex one. There just aren’t that many different ways to do things, so all well-written Go code tends to look the same. It’s easy to just dive into an unfamiliar service and understand what it’s doing.
fmt.Println("Gopher's Diner Breakfast Menu") for dish, price := range menu { fmt.Println(dish, price) }
(In the Code Club series, I do exactly that: pick Go projects semi-randomly from GitHub and explore them with a group of Go beginners, to see how much of the code we can understand. It always turns out to be more than we expected!)
Although the core language is small, Go’s standard library is very powerful. That means your learning curve will also need to include the parts of the standard library that you need, not just Go syntax. On the other hand, moving functionality out of the language and into the standard library means that you can focus on learning only the libraries that are relevant to you right now.
Go is also designed for software development at scale, with large codebases and large teams. In these situations, it’s important that new developers can get up to speed as quickly as possible.
With Go, you get things done—fast. Go is one of the most productive languages I’ve ever worked with. The mantra is: solve real problems today.
简便性 #
如果没人能搞懂怎么用它那么一个编程语言有多快是没有什么意义的。Go被认为是对类似C++的语言中日益增长的复杂性的一个蓄意的回应;它有非常少的语法,极其有限的关键字,以及,确实很少的特性。这意味着如果你要学到用Go来写一个实用程序花不了多久时间。
Go学起来难以置信的容易。我知道这是经常被拿来吹的优点,但我确实被我很快能变得有生产力给震惊到了。感谢这门语言,文档和工具,我可以在两天后写有趣又可以能提交的代码。
关键字也很简洁。确切而言,简洁不是简单,但一个小而简洁的语言确实比那些大而复杂的好学多了。没有那么多不同的路去做事,所以所有写得好的Go代码看上去都差不多。这就很容易去沉浸入那些陌生的服务而且知道它们在干什么。
fmt.Println("Gopher's Diner Breakfast Menu")
for dish, price := range menu {
fmt.Println(dish, price)
}
在Code Club系列中,我确实做到了:半随机地从GitHub中挑选Go项目并且和一群Go初学者探索它们,来看看我们能看懂多少代码。经常比我们预期要多!
即使核心语言很小,Go的标准库很强大。这意味着你的学习曲线需要包括你要知道的标准库,而不只是Go语法。另一方面,从语言的功能方面走出来到标准库,你就可以立即只学那些有关的库。
Go也为带有大型团队和大型代码库的成规模软件开发设计。在这些场景中,开发新手越快上手越好。
有了Go,你可以干活——很快。Go是我工作用到的最具生产力的语言之一。箴言就是:今天解决真正的问题。
Features #
Rust supports more complexity than several other programming languages, therefore, you can achieve more with it. For example, it supports generics.
Rust is specifically designed to include lots of powerful and useful features to help programmers do the most with the least code. For example, Rust’s match feature lets you write flexible, expressive logic quite concisely:
fn is_prime(n: u64) -> bool { match n { 0...1 => false, _ => !(2..n).any(|d| n % d == 0), } }
Because Rust does a lot, this means there’s a lot to learn, especially at the start. But that’s okay: there’s a lot to learn in C++ or Java, too, and you don’t get the advanced features that come with Rust, like memory safety. To criticise Rust for being a complex language misses the point: it’s designed to be expressive, which means having a lot of features, and in many situations that’s what you want from a programming language. There’s a learning curve, for sure, but once you’re up and running with it, you’ll be fine.
Rust competes for mindshare with C++ and D for programmers who are prepared to accept more complex syntax and semantics (and presumably higher readability costs) in return for the maximum possible performance.
特性 #
Rust比其他几种编程语言支持更多复杂性,因此你可以用Rust实现更多事。例如,它支持泛型。
Rust被特别设计包含很多强大且有用的特性,来帮助程序员用最少的代码做最多的事。举个例子,Rust的match特性让你简洁地写出灵活又有表现力的逻辑:
fn is_prime(n: u64) -> bool {
match n {
0...1 => false,
_ => !(2..n).any(|d| n % d == 0),
}
}
因为Rust做了很多,这并不意味着要学很多,特别是在一开始。但在一些地方是对的,C++要学一堆东西,Java也是,而且你不会得到Rust上有的高级特性,像内存安全。批评Rust成了复杂语言的观点经常忘记一点:他就是设计成为有丰富表现力,具有大量特性,而且在许多场景这些就是你想从编程语言中获得的。当然会有一个学习曲线,但一旦你上手并拿它做事,一切都会变好。
为了能获得最大可能的性能,Rust在记忆占用上很有竞争力,C++和D程序员需要准备接收大量复杂语法和语义(以及很可能随之而来的更高可读性上的花费)。
Concurrency #
Most languages have some form of support for concurrent programming (doing multiple things at once), but Go was designed for this job from the ground up. Instead of using operating system threads, Go provides a lightweight alternative: goroutines. Each goroutine is an independently executing Go function, which the Go scheduler will map to one of the OS threads under its control. This means that the scheduler can very efficiently manage a large number of concurrent goroutines, using only a limited number of OS threads.
Consequently, you can run millions of concurrent goroutines in a single program without creating serious performance problems. That makes Go the perfect choice for high-scale concurrent applications such as webservers and microservices.
Go also features fast, safe, efficient ways for goroutines to communicate and share data, using channels. Go’s concurrency support feels well-designed, and a pleasure to use. Reasoning about concurrent programs is hard in general, and building reliable, correct concurrent programs is a challenge in any language. Because it was built into the language from the start, though, instead of being an afterthought, concurrent programming in Go is about as simple and well-integrated as it could reasonably be.
Go makes it very easy to build a nicely factored application that takes full advantage of concurrency while being deployed as a set of microservices. Rust can do those things, too, but it’s arguably a bit tougher. In some respects, Rust’s obsession with preventing memory-related security vulnerabilities means that programmers have to go out of their way to perform tasks that would be simpler in other languages, including Go.
The concurrency story in Rust is very new, by comparison, and still stabilising, but it’s under very active development, so watch this space. For example, Rust’s rayon library provides a very elegant and lightweight way of turning sequential computations into parallel ones.
Having lightweight syntax for spawning Go routines and using channels are really nice. It really shows the power of syntax that such small details make concurrent programming feel so much nicer than in other languages.
While it may be a bit less straightforward to implement concurrent programs in Rust, it’s still possible, and those programs can take advantage of Rust’s guarantees about safety. A good example is the standard library’s Mutex class: in Go, you can forget to obtain a mutex lock before accessing something, but Rust won’t let you do that.
Go is focused on concurrency as a first class concept. That is not to say you cannot find aspects of Go’s actor oriented concurrency in Rust, but it is left as an exercise to the programmer.
并发 #
绝大多数语言都对并发编程(在某一瞬间内做多件事)有某种形式的支持,但Go完全就是为并发设计的。不是利用操作系统线程,Go提供了另一种轻量级的选择:goroutines。每个goroutine都会独立执行Go函数,而且在Go调度器的控制下会把它映射到操作系统中的一个线程。这意味着调度器可以非常高效管理大量并发的goroutine,只需要使用有限个数的操作系统线程。
最后你可以在一个程序中运行上百万的并发goroutine,不会产生严重的性能问题。这使得Go成为大规模并发程序的完美选择,例如web服务器和微服务。
Go具备goroutine使用channel去通信和共享数据的特性,这快捷,安全又有效率。Go的并发支持设计得不错,用起来也很好。一般而言理解并发程序是件难事,建造可靠又正确的并发程序在任何语言上都是个挑战。因为Go从一开始就把并发机制内建与语言中,而不是事后才想起添加,在Go上进行并发编程理解简单又整合良好。
Go让建造分解良好的程序变得容易,同时利用了并发的全部优点,又可以部署为一系列微服务。Rust也能做这些事,但它还是有点难。在某些方面,Rust过于关注防止内存相关的安全受到损害,意味着程序员不得不偏离自己的方式去执行一些任务,而这在其他语言会比较容易,比如Go。
Rust的并发机制相对而言非常新,仍能保持稳定,但这仍处于非常频繁的开发当中,所以让我们拭目以待。举一个例子,Rust的rayon库提供了一个非常优雅且轻量的实现方式,来把串行计算转换为并行计算。
使用轻量语法来产生goroutine和使用channel固然美好。它真切展示了语法的力量,如此小的细节使得并发编程比别的语言更加优美。
在Rust中实现并发程序会稍微或许不那么直观,但同时这些程序是有可能利用Rust在安全保障上面的优势。一个不错的例子是标准库中的Mutex类:在Go你在访问某物前可能忘记获取Mutex锁,但Rust不会让你这样做。
Go聚焦于让并发成为第一公民概念。但这并不是说你不能在Rust中找到类似Go的面向actor的并发机制,这可能留下来成为程序员的练习。
Safety #
We saw earlier that both Go and Rust aim, in different ways, to prevent a large class of common programming errors, to do with memory management. But Rust in particular goes to great lengths to ensure that you can’t do something unsafe that you didn’t mean to do.
Rust’s very strict and pedantic compiler checks each and every variable you use and every memory address you reference. It avoids possible data race conditions and informs you about undefined behavior. Concurrency and memory safety issues are fundamentally impossible to get in the safe subset of Rust.
This is going to make programming in Rust a different experience to almost all other languages, and it may be a challenging one at first. But for many people, the hard work is worth it.
For me the key advantage of Rust is a feeling that the compiler has my back and won’t let through any bug it could possibly detect (seriously, it feels like magic sometimes).
—Grzegorz Nosek
Many languages, including Go, have facilities to help programmers avoid mistakes, but Rust takes this to a new level, so that potentially incorrect programs won’t even compile.
With Rust, the library programmer has a lot of tools to prevent her users making mistakes. Rust gives us the ability to say that we own a specific piece of data; it’s not possible for anything else to claim ownership, so we know nothing else will be able to modify it. I can’t think of a time I’ve ever been given this many tools to prevent accidental misuse before. It’s a wonderful feeling.
“Fighting with the borrow checker” is a common syndrome for new Rust programmers, but in most cases the problems that it finds are genuine bugs (or at least potential bugs) in your code. It may force you to fundamentally re-architect your program to avoid running into these issues; and that’s a good thing, when correctness and reliability are your top priority. What’s the point of a language that doesn’t change the way you program? The lessons that Rust teaches about safety can be useful when you’re working in other languages, too.
If you choose Rust, usually you need the guarantees that the language provides: safety against null pointers and data races, predictable runtime behaviour, and total control over the hardware. If you don’t require any of these features, Rust might be a poor choice for your next project. That’s because these guarantees come with a cost: ramp-up time. You’ll need to unlearn bad habits and learn new concepts. Chances are, you will fight with the borrow checker a lot when you start out.
How challenging you find Rust’s programming model probably depends on what previous experience you have in other languages. Python or Ruby programmers may find it restrictive; others will be delighted.
If you’re a C or C++ programmer who’s spent weeks chasing down memory safety bugs in those languages, you’ll really appreciate Rust. “Fighting the borrow checker” becomes “The compiler can detect that? Cool!”
—Grzegorz Nosek
安全 #
之前我们看到了Go和Rust使用不同方式来进行内存管理,以此避免很大一类共同的编程错误。但Rust在这一步上走得更远来确保你不会做那些不安全而且并非故意为之的行为。
Rust过于严格和迂腐的编译器检查你使用的每一个变量和引用的每一个内存地址。它避免了可能的数据竞争条件和告知你未定义的行为。并发和内存安全问题在Rust的安全机制中是根本不可能出现的。
这使得在Rust编程对于其他几乎所有语言都是与众不同的体验,而且在一开始就可能是一个挑战。但对于大多数人来讲,辛苦是值得的。
来我来说Rust的关键优势是感觉编译器保证我的大后方安全,而且不会通过它可能监测到的任何bug(不说玩笑话,有时候就像魔法)。
—Grzegorz Nosek
许多语言,包括Go,提供一些功能帮助程序员避免错误,但Rust将此提升一个新的台阶,因此潜在不正确的程序甚至编译都不可以。
有了Rust,库程序员有一大堆工具可以防止库的用户产生错误。Rust给予我们某种能力来说我们拥有某个数据片段;这使得其他东西试图索取拥有权是不可能的,所以我们知道它不会被修改。之前我从未想过我被给予如此之多的工具来防止意外误用。感觉棒呆了。
“和borrow checker搏斗”是新晋Rust程序员的共同经历,但大多情况下它查到的问题确实是代码中的真正存在的bug(至少是潜在的bug)。它或许会迫使你把程序从根本上重构一遍来防止运行的时候出现这些问题;这是好的,当你把正确性和可靠性列为最高优先级。用一门没有改变你编程方式的语言有什么意义呢?Rust在安全上教的一课会在你使用其他语言时也能发挥用处。
如果你选择了Rust,你经常需要保证满足语言的这些要求:对空指针和数据竞赛的安全性,可预测的运行时行为,以及对于硬件的完全控制。如果你不具备任一这些特点,Rust或许在你下一个项目将成为糟糕的选择。因为这些要求都需要同一个代价:爬坡时间。你需要忘却陋习和学习新知。而且很可能你在一开始在borrow checker中挣扎很长一段时间。
在Rust编程模型上有多挑战性或许取决于你之前在别的语言的经历。Python或Ruby程序员或许觉得束手束脚;其他语言的则会挺开心的。
如果你是一个C/C++程序员,花费数周时间在语言中追查内存安全bug,你会非常欣赏Rust。“和borrow checker搏斗”会变成“这编译器连这个都能查?真不错!”
—Grzegorz Nosek
Scale #
Today’s server programs comprise tens of millions of lines of code, are worked on by hundreds or even thousands of programmers, and are updated literally every day. Go was designed and developed to make working in this environment more productive. Go’s design considerations include rigorous dependency management, the adaptability of software architecture as systems grow, and robustness across the boundaries between components.
When you’re working on a problem by yourself or in small teams, the choice of a simple language or a rich language is a matter of preference. But as the software grows bigger and more complex, and the teams grow larger, the differences really start to show. For large applications and distributed systems, speed of execution is less important than speed of development: a deliberately minimal language like Go reduces the ramp-up time for new developers, and makes it easier for them to work with a large codebase.
With Go, it’s easier as a junior developer to be more productive, and harder as a mid-level developer to introduce brittle abstractions that will cause problems down the line. For these reasons, Rust is less compelling than Go for enterprise software development.
When it comes to software development in the large, clear is better than clever. Go’s limitations actually make it more suitable for enterprises and big organisations than more complex and powerful languages such as Rust.
规模 #
今天服务器程序包含了数千万行的代码,由成百甚至上千名程序员协作,而且每一天都在更新。Go就是为了在这种环境下更具生产力设计和开发出来的。Go的设计考量包括了缜密的依赖管理,随系统成长的软件架构的适应性,还有组件边界的稳健性。
当你独身一人或者在一个小团队解决一个问题,对于特性简洁或者丰富的语言上的选择通常是个人偏好的问题。但随着软件变得更加庞大和复杂,以及团队规模增大,这中间的区别便开始真正展现。对于大型应用和分布式系统,执行速度让位于开发速度:一个特意最简的语言比如Go将减少新人开发者的上手时间,而且这使得他们在大型代码库中的工作变得容易。
有了Go,初级开发者要变得更有生产力会更加容易,但对于中级开发者引入脆弱的抽象将会在生产中造成麻烦。基于此,对企业软件开发而言Rust不像Go那么有吸引力。
当软件开发到达大规模之时,清晰比聪明更好。Go的限制确实令它比其他更复杂更强劲的语言,比如说Rust,更适合企业和大型组织。
The differences #
Although Rust and Go are both popular, modern, widely-used languages, they’re not really competitors, in the sense that they’re deliberately targeting quite different use cases. Go’s whole approach to programming is radically different to Rust’s, and each language will suit some people while irritating others. That’s absolutely fine, and if both Rust and Go did more or less the same things in more or less the same way, we wouldn’t really need two different languages.
So can we get a sense of the respective natures of Rust and Go by finding issues on which they take drastically different approaches? Let’s find out.
区别 #
尽管Rust和Go都是流行且广泛使用的现代语言,它们并不是真正的竞争对手,就这方面而言它们都刻意面向及其不同的使用场景。Go在编程上的整套方法论和Rust有天壤之别,每个语言在适合一些人的同时让另外一拨人感到不快。这是好事,而且假若Rust和Go用差不多相同的方式做到差不多相同的事,我们干嘛还需要两门不同的语言。
所以通过查找一些问题,在它们采取截然不同的方式解决这些问题中,我们是否可以得到Rust和Go各自本质的笼统感受?那让我们开始吧。
Garbage collection #
“To garbage-collect, or not to garbage-collect” is one of those questions that has no right answer. Garbage collection, and automatic memory management in general, makes it quick and easy to develop reliable, efficient programs, and for some people that makes it essential. But others say that garbage collection, with its performance overhead and stop-the-world pauses, makes programs behave unpredictably at run-time, and introduces unacceptable latency. The debate rumbles on.
Go is a very different language to Rust. Although both can vaguely be described as systems languages or replacements for C, they have different goals and applications, styles of language design, and priorities. Garbage collection is a really huge differentiator. Having GC in Go makes the language much simpler and smaller, and easy to reason about.
Not having GC in Rust makes it really fast (especially if you need guaranteed latency, not just high throughput) and enables features and programming patterns that are not possible in Go (or at least not without sacrificing performance).
垃圾回收机制 #
“垃圾回收,还是不回收”是没有正确答案的问题之一。垃圾回收,或者广义的自动内存管理,使得快捷方便地开发可靠又高效的程序,而且对于一些人这是必需的。但另一些人争辩说垃圾回收带来的性能开支和stop-the-world的暂停,让程序在运行时变得不可预测,并引入了不可接受的延迟。这个争论仍在绵延下去。
Go是一个非常不同于Rust的语言。尽管都被大致描述为系统语言或者C的替代品,它们有着不同的目标和应用,语言设计的风格,还有优先考虑的事情。垃圾回收就是一个巨大的分野。拥有垃圾回收使得Go变得更简洁和迷你,而且也容易理解。
在Rust中没有垃圾回收使得这门语言非常快速(特别当你需要保证延迟,而不仅仅是吞吐量)和拥有Go不可能有的特性和编程模式(或者至少需要牺牲性能)。
Close to the metal #
The history of computer programming has been a story of increasingly sophisticated abstractions that let the programmer solve problems without worrying too much about how the underlying machine actually works. That makes programs easier to write and perhaps more portable. But for many programs, access to the hardware, and precise control of how the program is executed, are more important. Rust aims to let programmers get “closer to the metal”, with more control, but Go abstracts away the architectural details to let programmers get closer to the problem.
Both languages have a different scope. Golang shines for writing microservices and for typical “DevOps” tasks, but it is not a systems programming language. Rust is stronger for tasks where concurrency, safety and/or performance are important; but it has a steeper learning curve than Go.
贴近硬件 #
计算机编程的历史本身,就是逐渐复杂的抽象让程序员不需要了解太多底层硬件的运行机制,就可以解决问题。这使得程序更易编写和可能更轻便。但对于许多程序,对硬件的访问,还有对于程序如何执行的精确控制,这些更加重要。Rust致力于通过更多控制,让程序员贴近底层,但Go抽象了架构细节使得程序员更贴近问题。
这两种语言有不同的范围。Golang在编写微服务和典型的“DevOps”任务上大放异彩,但它不是一种系统编程语言。Rust在并发,安全和/或性能更加重要的任务上更为强大;但它有着比Go更陡峭的学习曲线。
Must go faster #
I’ve written elsewhere that performance is less important than readability for most programs. But when performance does matter, it really matters. Rust makes a number of design trade-offs to achieve the best possible execution speed. By contrast, Go is more concerned about simplicity, and it’s willing to sacrifice some (run-time) performance for it. But Go’s build speed is unbeatable, and that’s important for large codebases.
Rust is faster than Go. In the benchmarks above, Rust was faster, and in some cases, an order of magnitude faster. But before you run off choosing to write everything in Rust, consider that Go wasn’t that far behind it in many of those benchmarks, and it’s still much faster than the likes of Java, C#, JavaScript, Python and so on.
If what you need is top-of-the-line performance, then you’ll be ahead of the game choosing either of these two languages. If you’re building a web service that handles high load, that you want to be able to scale both vertically and horizontally, either language will suit you perfectly.
必须够快 #
我曾在别的地方写了在大多数程序上性能比可读性不那么重要。但当性能确实重要时,它真的重要。Rust用了许多设计上的权衡来达到可能最佳的执行速度。相反,Go更关心简洁性,而且为此它更愿意牺牲一些(运行时)性能。但Go的编译速度是无可匹敌的,而且对于大型代码库而言这很重要。
Rust比Go快。在上面的基准测试中,Rust更快,在某些情况下是数量级上的更快。但在你兴冲冲将所有程序用Rust编写前,要想到Go在许多基准测试中并不比Rust落后多少,而且它仍然比Java,C#,JavaScript,Python诸如此辈快得多。
如果你需要的是顶级性能,你可以选择两种语言中的其中一种来取得领先优势。如果你是要创建一个网络服务,处理高负载,并且你现在纵向和横向伸缩,这两种语言都能完美满足你。
Correctness #
On the other hand, a program can be arbitrarily fast if it doesn’t have to work properly. Most code is not written for the long term, but it’s often surprising how long some programs can stay running in production: in some cases, many decades. In these situations it’s worth taking a little extra time in development to make sure that the program is correct, reliable, and won’t need a lot of maintenance in the future.
My take: Go for the code that has to ship tomorrow, Rust for the code that has to keep running untouched for the next five years.
—Grzegorz Nosek
While both Go and Rust are great choices for any serious project, it’s a good idea to make yourself as well-informed as possible about each language and its characteristics. Ultimately, it doesn’t matter what anyone else thinks: only you can decide which is right for you and your team.
If you want to develop faster, perhaps because you have many different services to write, or you have a large team of developers, then Go is your language of choice. Go gives you concurrency as a first-class citizen, and does not tolerate unsafe memory access (neither does Rust), but without forcing you to manage every last detail. Go is fast and powerful, but it avoids bogging the developer down, focusing instead on simplicity and uniformity. If on the other hand, wringing out every last ounce of performance is a necessity, then Rust should be your choice.
正确性 #
在另一方面,一个程序可以运行得任意快但不一定正确。绝大多数代码并不是为了长期存在编写的,但一些程序总是惊人地长期运行在生产环境中:在一些情况下,可达数十年。在这些场景中,在开发中值得花费稍微额外一点时间,来确保这些程序正确,可靠并且将来不会需要大量维护。
我的抉择:对于明天发布的代码用Go,对于接下来五年保持运行而不动的代码用Rust。
—Grzegorz Nosek
Go和Rust对于任一严肃的项目都是不错的选择,同时让自己尽可能详细了解每个语言及其特性。最后,别人怎么想的不重要:只有你能决定哪个对你和你的团队是正确的。
如果你想快速开发,或许因为你有许多不同服务要去完成,抑或你有一个许多开发者组成的庞大团队,那么Go是你的语言之选。Go像对待第一公民那样给予你并发机制,而且不用忍受危险的内存访问(Rust不是),但不会强制你管理每一个细节。Go又快又强大,但它不会让开发者陷进去,而是聚焦在简洁和一致上。如果另一方面,榨干每一丝性能是必须的,那么Rust应该是你的选择。
Conclusion #
I hope this article has convinced you that both Rust and Go deserve your serious consideration. If at all possible, you should aim to get at least some level of experience in both languages, because they will be incredibly useful to you in any tech career, or even if you enjoy programming as a hobby. If you only have time to invest in learning one language well, don’t make your final decision until you’ve used both Go and Rust for a variety of different kinds of programs, large and small.
And knowledge of a programming language is really only a small part of being a successful software engineer. By far the most important skills you’ll need are design, engineering, architecture, communication, and collaboration. If you excel at these, you’ll be a great software engineer regardless of your choice of language. Happy learning!
结论 #
我希望这篇文章可以让你相信Rust和Go都值得你严肃的考虑。如果尽一切可能,你应该致力于在这两种语言上取得至少某一级别的经验,因为它们都是难以置信的有用,不管对你的技术职业生涯,或甚至如果你把编程作为乐趣。如果你只有投资学习一门语言的时间,直到你在不同种类的程序上应用Go和Rust之前,不要做出最终决定。
还有关于编程语言的只是成为成功的软件工程师中的很小一部分。目前你需要的最重要的技巧是设计,开发,架构,沟通,以及协作。如果你都精通了,无论你选择何种语言,你将是一个不错的软件工程师。学习愉快!