About the author: Nick Cameron is a research engineer at PingCAP and a core member of Rust.

Thanks to Rust’s Chinese community partners for translating and revising:

  • Translation: Shang Zhuo burning
  • Review: Wu Cong, Zhang Handong

For the past few weeks, I’ve been writing programs in the Go language. This was the first time I used Go on a large and important project. While researching Rust’s nature, I also read a lot about Go, including playing with examples and writing toy programs. But actually programming it is a completely different experience.

I thought it would be fun to write about the experience. In this article, I’ll try to avoid making too many comparisons between Go and Rust, but since I switched from Rust to Go, it’s hard not to include some comparisons. It should be noted in advance that I favor Rust, but try to be objective.

The overall impression

Programming with Go feels great. The library program has everything I want, the overall implementation is more perfect. The learning experience is smooth, and IT has to be said that Go is a well-designed language for practical use. For example, once you know the syntax of Go, you can carry over idiomatic expressions from other languages into Go. Once you’ve learned some Go, it’s relatively easy to speculate about other features of the language. With some knowledge from other languages, I was able to read and understand the Go code without much searching (Google).

Go has fewer pain points and is much more productive than C/C++, Java, Python, etc. However, it is still contemporary with these languages. Although it has learned some lessons from other languages, and I even personally think it is probably the best language of its generation, it definitely belongs to its generation. This is an incremental improvement, not a reinvention (to be clear, this is not meant to be a critique of its value, as incremental improvements are usually good from a software engineering perspective). A good example is nil: languages like Rust and Swift have eliminated the concept of null and a whole class of related errors. Go reduces some of the risk: there are no null values, and there is a distinction between nil and zero. But the core idea remains the same, and the common run-time error of nulling-pointer references also occurs.

learnability

Go is very easy to learn. I know people tout this a lot, but I’ve been shocked by how quickly my productivity has increased. Thanks to the Go language and its documentation and tools, I was able to write “valuable”, deliverable code in just two days.

Several factors contribute to learnability:

  • Go is lean. A lot of languages try to look small, but Go really does it (which is basically a good thing, and I’m impressed with the self-discipline).

  • The standard library is excellent (and, again, small). It is easy to find and use libraries from the ecosystem.

  • There is almost nothing that is not available in other languages. Go takes a lot of content from other pre-existing languages, refines it, and puts it all together nicely. It goes to great lengths to avoid being unconventional.

Boring boilerplate code

Go code can get very repetitive very quickly. This is due to the lack of macros or generics as mechanisms to reduce duplication (interfaces, while good for abstraction, are not as useful in reducing code duplication). I end up writing a lot of functions that are exactly the same except of different types. Error handling can also lead to duplication. Many functions like if err! = nil {return err} is even more boilerplate code than really valuable code. The use of generics or macros to reduce boilerplate code is sometimes criticized on the grounds that it should not make the code less readable by making it easier to write. I’ve found that Go provides just the opposite example. While copying and pasting code is often fast and easy, reading code can be frustrating because you have to ignore a lot of irrelevant code or find subtle differences in a lot of the same code.

Something I like

  • Compile time: absolutely fast, certainly much faster than Rust. But in reality, it’s not as fast as I expected (for medium to large projects, I feel it’s just close to C/C++, or a little faster. I’m looking forward to just-in-time compilation.

  • Goroutines and channels: To its credit, Go provides lightweight syntax for generating coroutines and using channels. Even though it’s a small detail, it makes the concurrent programming experience of Go superior to other languages, and it really reveals the power of syntax.

  • Interfaces: They are not complicated, but they are easy to understand and use, and are useful in many places.

  • if … ; . {} syntax: It’s nice to be able to limit the scope of variables to if statements. This has a similar effect to the if lets in Swift and Rust, but is more versatile (Go does not have the same pattern matching as Swift and Rust, so it cannot use if lets).

  • The tests and documentation comments are easy to use.

  • The Go toolchain is very friendly: it puts everything in one place, rather than having to use multiple tools on the command line.

  • Having a garbage collector (GC) : Not having to worry about memory management really makes programming easier.

  • Variable parameters.

Something I don’t like

The following is in no particular order.

  • Nil slice: You know nil, nil slice and empty slice are all different, and I’m sure we only need two of them, not the third.

  • Enumeration types are not first citizens: Simulating enumerations with constants feels like a step backwards.

  • Do not allow circular references: This actually limits the availability of packages in partitioned project modules, because it encourages piling up lots of files in a package (or having lots of fragmented packages, which is just as bad if files that should be together are scattered around).

  • Switch allows missing matches.

  • for … The range statement returns a pair of indexes/values. It’s easy to just get the index (just ignore the value); But to get only the value, you need to explicitly declare it. In my opinion, this should be reversed, because in most cases, I need the value more than the index.

  • Grammar:

    • There is a discrepancy between definition and purpose.
    • Compilers can sometimes be picky (for example, requiring or disallowing trailing commas); This can be alleviated with good tools, but sometimes it can still lead to annoying extra steps.
    • When using multivalued return types, parentheses are required over the types, butreturnYou don’t need it in statements.
    • Declaring a structure requires two keywords (typestruct).
    • Using uppercase nomenclature to mark public or private variables looks like Hungarian nomenclature, but worse.
  • Implicit interface. I know it shows up in things I like, too, but sometimes it can be really annoying — especially when you’re trying to figure out all the types that implement that interface, or which interfaces are implemented for a given type.

  • You can’t write functions with receivers in different packages, so even if the interface is “duck type,” you can’t implement it for a type in another package, making them much less useful.

  • Also, as I mentioned earlier, Go lacks generics and macros.

consistency

As a language designer and programmer, perhaps what surprises me most about Go is the frequent inconsistencies between what’s built in and what’s available to the user. One of the goals of many languages is to remove as much compiler magic as possible and make built-in functionality available to users. Operator overloading is a simple but controversial example. But Go has a lot of magic! It’s easy to run into the problem of not being able to do what the built-in features do.

Some things impressed me:

  • The syntax for returning multiple values and channels is great, but the two cannot be used together because there is no tuple type.

  • You can use for… The range statement iterates over arrays and slices, but not over other collections because it lacks the concept of iterators.

  • Functions like len or Append are global functions, but your own functions cannot be converted to global functions. These global functions can only use built-in types. Even if Go is “not generic,” they can be generic.

  • Without operator overloading, == would be annoying. Because that means you can’t use custom types as keys in a dictionary unless they’re comparable. This property is derived from the type structure and cannot be overridden by the programmer.

conclusion

Go is a simple, small, and delightful language. It has a few nooks and cranny, but most of them are carefully designed. It’s incredibly fast to learn and avoids some of the lesser-known features of other languages.

Go is also a distinct language from Rust. While both can be loosely described as “systems languages” or “alternatives to C,” their design goals, application domains, language styles, and priorities are not the same. Garbage collection does make a big difference: Using GC makes Go simpler, smaller, and easier to understand. Not using GC makes Rust incredibly fast (especially if you need to guarantee latency, not just high throughput) and enables features or programming patterns that are impossible to achieve in Go (or at least impossible to achieve without sacrificing performance).

Go is a compiled language, its runtime is well implemented, and its speed is unquestionable. Rust is also a compiled language, but with a much smaller runtime, it’s really fast. In the absence of other limitations, I think the choice between Go and Rust really means a trade-off:

  • On the one hand, Go has a shorter learning curve and simpler programs (which means faster development);

  • Rust, on the other hand, is really high-performance and has a more expressive type system (which makes the program safer and means faster debugging and error finding).

Attached: original English article

Please leave a comment below to tell us about your Go & Rust experience: from entry to abandonment, from abandonment to mastery, the pits you have stepped in, the tears you have shed… Or their killer advantage.

⚠️ Rational discussion, Peace & Love.