Rust Essentials

4.3 (3 reviews total)
By Ivo Balbaert
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. Starting with Rust

About this book

Starting by comparing Rust with other programming languages, this book will show you where and how to use Rust. It will discuss primitive types along with variables and their scope, binding and casting, simple functions, and ways to control execution flow in a program.

Next, the book covers flexible arrays, vectors, tuples, enums, and structs. You will then generalize the code with higher-order functions and generics applying it to closures, iterators, consumers, and so on. Memory safety is ensured by the compiler by using references, pointers, boxes, reference counting, and atomic reference counting. You will learn how to build macros and crates and discover concurrency for multicore execution.

By the end of this book, you will have successfully migrated to using Rust and will be able to use it as your main programming language.

Publication date:
May 2015
Publisher
Packt
Pages
184
ISBN
9781785285769

 

Chapter 1. Starting with Rust

Rust is a programming language that is developed by Mozilla Research and backed up by a big open source community. Its development started in 2006 by language designer Graydon Hoare. Mozilla began sponsoring it in 2009, and it was first presented officially in 2010. The work on it went through a lot of iterations, culminating on May 15 2015 with the first stable production version 1.0.0, which was made by the Rust Project Developers who consisted of the Rust team at Mozilla and an open source community of over 900 contributors. Rust is based on clear and solid principles. It is a systems programming language, equaling C and C++ in its capabilities. It rivals idiomatic C++ in speed, but it lets you work in a much safer way by forbidding the use of code that could cause program crashes due to memory problems. Moreover, Rust has the built-in functionality necessary for concurrent execution on multicore machines; it makes concurrent programming memory safe without garbage collection—it is the only language that does this. Rust also eliminates the corruption of shared data through concurrent access, also known as data races.

This chapter will present you with the main reasons why Rust's popularity and adoption are steadily increasing. Then, we'll set up a working Rust development environment.

We will cover the following topics:

  • The advantages of Rust

  • The trifecta of Rust: safety, speed, and concurrency

  • Using Rust

  • Installing Rust

  • The Rust compiler – rustc

  • Building our first program

  • Working with Cargo

  • Developer tools

 

The advantages of Rust


Mozilla is the company that is known for its mission to develop tools for and drive the evolution of the Web based on open standards, most notably through its flagship browser Firefox. Every browser today, including Firefox, is written in C++ by using some 12,900,992 lines of code for Firefox and 4,490,488 lines of code for Chrome. This enables programs to be fast, but it is inherently unsafe because the memory manipulations allowed by C and C++ are not checked for validity. If the code is written without the utmost programming discipline on the part of the developers, then program crashes, memory leaks, segmentation faults, buffer overflows, and null pointers can occur at program execution. Some of these can result in serious security vulnerabilities, which are all too well-known in existing browsers. Rust is designed from the ground up to avoid these kinds of problems.

On the other side of the programming-language spectrum, we have Haskell, which is widely known to be a very safe and reliable language, but with very little or no control of the level of memory allocation and other hardware resources. We can plot different languages along this control—safety axis, and it seems that when a language is safer, it loses low-level control; the inverse is also true: a language that gives more control over resources provides much less safety, shown as follows:

Rust (http://www.rust-lang.org/) is made to overcome this dilemma by providing the following features:

  • High safety through its strong type system

  • Deep but safe control over low-level resources (as much as C/C++) so that it runs close to the hardware

Rust lets you specify exactly how your values should be laid out in memory and how that memory should be managed; this is why it works well at both ends of the control and safety line. This is the unique selling point of Rust: it breaks the safety-control dichotomy that, before Rust, existed in programming languages. With Rust, control and safety can be achieved together without losing performance.

Rust can accomplish both these goals without a garbage collector, in contrast to most modern languages such as Java, C#, Python, Ruby, Go; in fact Rust doesn't even have a garbage collector yet (though one is planned). Rust is a compiled language: the strict safety rules are enforced by the compiler so that they do not cause runtime overhead. As a consequence, Rust can work with minimal runtime or even no runtime at all; so, it can be used for real time or embedded projects, and it can easily integrate with other languages or projects.

Rust is meant for developers and projects where not only performance and low-level optimizations are important, but where there is also a need for a safe and stable execution environment. Moreover, Rust adds a lot of high-level functional programming techniques within the language so that it feels like a low-level and a high-level language at the same time.

 

The trifecta of Rust – safety, speed, and concurrency


Rust is not a revolutionary language with new cutting-edge features, but it incorporates a lot of proven techniques from older languages while massively improving upon the design of C++ in matters of safe programming.

The Rust developers designed Rust to be a general-purpose and multi-paradigm language. Like C++, it is an imperative, structured, and object-oriented language. Besides this, it inherits a lot from functional languages and also incorporates advanced techniques for concurrent programming.

In Rust, the typing of variables is static (because Rust is compiled) and strong. However, unlike Java or C++, the developer is not forced to indicate the types for everything as the Rust compiler is able to infer the types in many cases.

C and C++ are known to be haunted by a series of problems that often lead to program crashes or memory leaks which are notoriously difficult to debug and solve. Think about dangling pointers, buffer overflows, null pointers, segmentation faults, data races, and so on. The Rust compiler (called rustc) is very intelligent and can detect all these problems while compiling your code, thereby guaranteeing memory safety during execution. This is done by the compiler by retaining complete control over memory layout, without needing the runtime burden of garbage collection (see Chapter 6, Pointers and Memory Safety). In addition, its safety also implies much less possibilities for security breaches.

Rust compiles native code like Go and Julia. However, in contrast to these two, Rust doesn't need runtime with garbage collection. In this respect, it also differs from Java JVM and the languages that run on the JVM, such as Scala and Clojure. Most other popular modern languages such as .NET with C# and F#, JavaScript, Python, Ruby, Dart, and so on, all need a virtual machine and garbage collection.

As one of its mechanisms for concurrency, Rust adopts the well-known actor model from Erlang. Lightweight processes called threads perform work in parallel. They do not share heap memory but communicate data through channels, and data races are eliminated by the type system (see Chapter 8, Concurrency and Parallelism). These primitives make it easy for programmers to leverage the power of many CPU cores that are available on current and future computing platforms.

The rustc compiler is completely self hosted, which means that it is written in Rust and can compile itself by using a previous version. It uses the LLVM compiler framework as its backend (for more information on LLVM compiler framework, go to http://en.wikipedia.org/wiki/LLVM) and produces natively executable code that runs blazingly fast because it compiles to the same low-level code as C++ (To see an example of its speed, go to http://benchmarksgame.alioth.debian.org/u64q/rust.php.).

Rust is designed to be as portable as C++ and run on widely used hardware and software platforms; at present, it runs on Linux, Mac OS X, Windows, FreeBSD, Android, and iOS. It can call C's code as simply and efficiently as C can call its own code, and conversely, C can also call Rust code (see Chapter 9, Programming at the Boundaries). The following is the logo of Rust:

Other Rust characteristics that will be discussed in more detail in later chapters are as follows:

  • Its variables are immutable by default (see Chapter 2, Using Variables and Types)

  • Enums (see Chapter 4, Structuring Data and Matching Patterns)

  • Pattern matching (see Chapter 4, Structuring Data and Matching Patterns)

  • Generics (see Chapter 5, Generalizing Code with Higher-order Functions and Parametrization)

  • Higher-order functions and closures (see Chapter 5, Generalizing Code with Higher-order Functions and Parametrization)

  • The interface system called traits (see Chapter 5, Generalizing Code with Higher-order Functions and Parametrization)

  • A hygienic macro system (see Chapter 7, Organizing Code and Macros)

  • Zero-cost abstractions, which means that Rust has higher-language constructs, but these do not have an impact on performance

In conclusion, Rust gives you ultimate power over memory allocation as well as removing many security and stability problems that are commonly associated with native languages.

Comparison with other languages

Dynamic languages such as Ruby or Python give you the initial coding speed, but you pay the price later when you have to write more tests, runtime crashes, or even production outages. The Rust compiler forces you to get a lot of things right at compile-time, which is the least expensive place to identify and fix bugs.

Rust's object orientation is not that explicit or evolved as common object-oriented languages such as Java, C#, and Python as it doesn't have classes. Compared with Go, Rust gives you more control over memory and resources, so lets you code on a lower level. Go also works with a garbage collector, and it has no generics or a mechanism to prevent data races between its goroutines that are used in concurrency. Julia is focused on numerical computing performance; it works with a JIT compiler and doesn't give you that low-level control that Rust gives.

 

Using Rust


It is clear from the previous sections that Rust can be used in projects that normally use C or C++. Indeed, many regard Rust as a successor or a replacement of C and C++. Although Rust is designed to be a systems language, it has a broad range of possible applications due to its richness of constructs, making it an ideal candidate for applications that fall into one or all of the following categories:

  • Client applications, such as browsers

  • Low-latency, high-performance systems, such as device drivers, games, and signal processing

  • Highly distributed and concurrent systems, such as server applications

  • Real-time and critical systems, such as operating systems or kernels

  • Embedded systems (that require a very minimal runtime footprint) or a resource-constrained environment, such as a Raspberry Pi, Arduino, or robotics

  • Tools or services that can't support the long warm-up delays that are common in Just In Time (JIT) compiler systems and need instantaneous startup

  • Web frameworks

  • Large-scale, high-performance, resource intensive, and complex software systems

Rust is especially suited when code quality is important, that is for:

  • Modestly-sized or larger developer teams

  • Code for long-running production use

  • Code with a longer lifetime that requires regular maintenance and refactoring

  • Code for which you would normally write a lot of unit tests to safeguard it

Even before the appearance of Rust 1.0, two companies already use it in production:

Servo

Mozilla uses Rust as the language for writing Servo, its new web browser engine that is designed for parallelism and safety (https://github.com/servo/servo).

Due to the design of Rust's compiler, many kinds of browser security bugs are prevented automatically. In 2013, Samsung got involved, porting Servo to Android and ARM processors. Servo itself is an open source project with more than 200 contributors. It is under heavy development, and among other things, it has already implemented its own CSS3 and HTML5 parser in Rust. It passed the web compatibility browser test ACID2 in March 2014 (http://en.wikipedia.org/wiki/Acid2/).

 

Installing Rust


The Rust compiler and tools can be downloaded from http://www.rust-lang.org/install.html in the binary (that is, executable) form. The platform comes for the three major operating systems (Linux 2.6.18 or a later version, OS X 10.7 or a later version, and Windows 7, Windows 8, and Windows Server 2008 R2) in both the 32- and 64-bit formats, and it is delivered as an installer or in an archive format. You should use the current official stable release 1.0 when you engage in professional work with Rust. If you would like to investigate or use the latest developments, install the nightly build version.

For Windows, double-click on the .exe installer to install the Rust binaries and dependencies. Adding Rust's directory to the search path for executables is an optional part of the installation, so make sure that this option is selected.

For Linux and Mac OS X, the simplest way is to run the following command in your shell:

curl -sSL https://static.rust-lang.org/rustup.sh | sh

Verify the correctness of the installation by showing Rust's version with rustc –V or rustc - -version, which produces an output like rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02).

Rust can be uninstalled by running C:\Rust\unins001.exe on Windows or /usr/local/lib/rustlib/uninstall.sh on Linux.

Rust has also been ported to Android OS on ARM processors and iOS.

A bare metal stack called zinc for running Rust in embedded environments can be found at http://zinc.rs/. However, at this moment, only the ARM architecture is supported by it.

The source code resides on GitHub (https://github.com/rust-lang/rust/) and if you want to build Rust from source, we refer you to https://github.com/rust-lang/rust#building-from-source.

 

The Rust compiler – rustc


The Rust installation directory containing rustc can be found on your machine in the following folder:

  • In Windows, at C:\Program Files\Rust 1.0\bin or a folder of your choice

  • On Linux or Mac OS X, it can be found by navigating to /usr/local/bin

If the Rust home folder was added to the search path for executables, rustc can be run from any command-line window. The Rust libraries can be found in the rustlib subfolder of the bin directory on Windows, or in /usr/local/lib/rustlib on Linux. Its HTML documentation can be found at C:\Rust\share\doc\rust\html on Windows or /usr/local/share/doc/html on Linux.

The rustc command has the following format: rustc [options] input.

The options are one letter directives for the compiler after a dash, such as -g or -W, or words prefixed by a double dash, such as - -test or - -no-analysis. All the options with some explanation are shown when invoking rustc -h. In the next section, we will verify our installation by compiling and running our first Rust program.

 

Our first program


Let's get started by showing a welcome message to the players of our game:

  1. Open your favorite text editor (such as notepad or gedit) for a new file and type in the following code:

    // code in Chapter1\code\welcome.rs
    fn main() {
        println!("Welcome to the Game!");
    }
  2. Save the file as welcome.rs.

    rs is the standard extension of Rust code files. Source file names may not contain spaces; if they contain more than one word, use an underscore _ as a separator; for example, start_game.rs.

  3. Then, compile it to native code on the command line with the following:

    rustc welcome.rs
    

    This produces an executable program welcome.exe on Windows or welcome on Linux.

  4. Run this program with welcome or ./welcome to get the following output:

    Welcome to the Game!
    

The output executable gets its name from the source file. If you want to give the executable another name, such as start, compile it with the -o output_name option:

rustc welcome.rs -o start

The rustc –O command produces a native code that is optimized for execution speed (which is equivalent to rustc -C opt-level=2; the most optimized code is generated for rustc –C opt-level = 3).

Compiling and running are separate, consecutive steps, contrary to dynamic languages such as Ruby or Python where these are performed in one step.

Let's explain the code a bit to you. If you have already worked in a C/Java/C# like environment, this code will seem quite familiar. As in most languages, execution of the code starts in a main() function, which is mandatory in an executable program.

In a larger project with many source files, the file containing the main() function would be called main.rs by convention.

We can see that main() is a function declaration because it is preceded by the keyword fn, which is short and elegant like most Rust keywords. () after main denotes the parameter list, which is empty here. The function's code is placed in a code block, which is surrounded by curly braces ({ }) where the opening brace is put by convention on the same line as the function declaration, but it is separated by one space. The closing brace appears after the code here, right beneath fn.

Our program has only one line, which is indented by four spaces to improve readability (Rust is not whitespace sensitive). This line prints the string, "Welcome to the Game!". Rust recognizes this as a string because it is surrounded by double quotes (" "). This string was given as an argument to the println! macro (! indicates that it is a macro and not a function). The code line ends with a semicolon (;), as most, but not all, code lines in Rust do (see Chapter 2, Using Variables and Types).

Perform the following exercises:

  • Write, compile, and execute a Rust program name.rs that prints out your name.

  • What is the smallest possible program in Rust in terms of code size?

The println! macro has some nice formatting capabilities and at the same time checks when compiling whether the type of variables is correct for the applied formatting (see Chapter 2, Using Variables and Types).

 

Working with Cargo


Cargo is Rust's package and dependency manager, and it is similar to Bundler, npm, pub, or pip for other languages. Although you can write Rust programs without it, Cargo is nearly indispensable for any large project; it works the same whether you work on a Windows, Linux, or a Mac OS X system. The installation procedure from the previous section includes the Cargo tool, so Rust is shipped with tooling included.

Cargo does the following things for you:

  • It makes a tidy folder structure and some templates for your project with the cargo new command

  • It compiles (builds) your code by using the cargo build command

  • It runs your project by using cargo run

  • If your project contains unit tests, it can execute them for you by using cargo test

  • If your project depends on packages, it will download them and build these packages according to the needs of your code by using cargo update

We'll introduce how to use Cargo now, and we'll come back to it later, but you can find more info here: http://doc.crates.io/guide.html.

Let's remake our first project welcomec using Cargo by performing the following steps:

  1. Start a new project welcomec using the following command:

    cargo new welcomec --bin
    

    The ––bin option tells Cargo that we want to make an executable program (a binary). This creates the following directory structure:

    A folder with the same name as the project is created; in this folder, you can put all kinds of general information such as a License file, a README file, and so on. In addition, a src subfolder is created that contains a template source file named main.rs. (This contains the same code as our welcome.rs file, but it prints out the string "Hello world!".)

    The file Cargo.toml (with capital C) is the configuration file or manifest of your project; it contains all the metadata that Cargo needs to compile your project. It follows the so-called TOML format (for more details about this format, go to https://github.com/toml-lang/toml) and contains the following text with information about our project:

    [package]
    name = "welcomec"
    version = "0.0.1"
    authors = ["Your name <[email protected]>"]"

    This file is editable, so other sections can be added. For example, you can add a section to tell Cargo that we want a binary with the name welcome:

    [[bin]]
    name = "welcome"
  2. We can build our project (no matter how many source files it contains) using the following command:

    cargo build
    

    This gives us the following output (on Linux):

    Compiling welcomec v0.0.1 (file:///home/ivo/Rust_Book/welcomec)
    

    Now, the following folder structure is produced:

    The directory target contains the executable welcome.

  3. To execute this program, run the following command:

    cargo run
    

    This produces the following output:

    Running `target/welcome`
    Hello, world!
    

Step 2 has also produced a file named Cargo.lock; this is used by Cargo to keep track of dependencies in your application. At the moment, the application only contains:

[root]
name = "welcomec"
version = "0.0.1"

The same file format is used to lock down the versions of libraries or packages that your project depends on. If your project is built in the future when updated versions of the libraries are available, Cargo will make sure that only the versions recorded in Cargo.lock are used so that your project is not built with an incompatible version of a library. This ensures a repeatable build process.

Perform the following exercise:

  • Make, build, and run a project name that prints out your name with Cargo.

The website at https://crates.io/ is the central repository for Rust packages or crates (as they are called) and contained 1700 crates as of the end of March 2015. You can search for crates using specific terms or browse them alphabetically or according to the number of downloads:

 

The developer tools


Since Rust is a systems programming language, the only thing that you need is a good text editor (but not a word processor!) for writing the source code, and everything else can be done by commands in a terminal session. However, some developers appreciate the functionalities offered by more fully fledged text editors which are specifically for programming or IDE's (short for integrated development environments). Rust is still young but a lot of possibilities have already come up on this front although some of them need to be updated in the latest Rust version.

Rust plugins exist for a host of text editors, such as Atom, Brackets, BBEdit, Emacs, Geany, GEdit, Kate, TextMate, Textadept, Vim, NEdit, Notepad++, and SublimeText. Most Rust developers work with Vim or Emacs. These come with a syntax highlighting, and code completion tool called racer; go to https://github.com/phildawes/racer.

Using Sublime Text

The plugins for the popular Sublime Text editor (http://www.sublimetext.com/3) are particularly pleasant to work with, and they don't get in your way. After you have installed Sublime Text (you might want to get a registered version), you must also install the Package Control package. (For instructions on how to do this, go to https://packagecontrol.io/installation).

Then, to install the Sublime Text Rust plugin, open the palette in Sublime Text (Ctrl + Shift + P or cmd + Shift + P on Mac OS X) and select Package Control | Install Package. Then, select Rust from the list, you will see something like the following screenshot:

Sublime Text is a very comprehensive text editor, which includes color schemes. The Rust plugin provides syntax highlighting and auto-completion. Type one or more letters, choose an option from the list that appears with an arrow key and press Tab to insert the code snippet, or simply select a list-option through a mouse click. To compile and execute Rust code, follow these steps:

  1. Mark Tools | Build System | Rust in the menu.

  2. Then, you can compile a source file by pressing Ctrl + B. Warnings or errors will appear in the lower pane; if everything is okay, a message similar to [Finished in 0.6s] will appear.

  3. Then, you can run the program by pressing Ctrl + Shift + B; again the output will appear beneath the code. Alternatively, you can use the menu items: Tools | Build and Tools | Run.

A SublimeLinter plugin exists that provides an interface to rustc, which is called SublimeLinter-contrib-rustc. It does additional checks on your code for stylistic or programming errors. You can install it, as explained earlier, through Package Control and then use it from the menu Tools | SublimeLinter. (For more details, go to https://github.com/oschwald/SublimeLinter-contrib-rustc.) There is also a code completion tool called racer; you can find the information on how to install it at https://packagecontrol.io/packages/RustAutoComplete.

Other tools

RustDT (http://rustdt.github.io/) is a new and promising Rust IDE based on Eclipse. On top of all the editing functionality offered by Eclipse, it is project-based using Cargo. Moreover it has code completion and debugging functionality (using the GDB debugger).

There are also plugins such as the following ones for IDEs at different states of completion:

You can test out the Rust code even without local installation with the Rust Play Pen: http://play.rust-lang.org/. Here you can edit or paste your code, and evaluate it.

The rusti is an interactive shell or Read-Evaluate-Print-Loop (REPL) that is being developed for Rust; this is common for dynamic languages, but it is remarkable for a statically compiled language. You can find it at https://github.com/murarth/rusti.

 

Summary


In this chapter, we gave you an overview of Rust's characteristics, where Rust can be applied, and compared it to other languages. We made our first program, demonstrated how to build a project with Cargo, and gave you choices to make a more complete development environment.

In the next chapter, we look at variables and types and explore the important concept of mutability.

About the Author

  • Ivo Balbaert

    Ivo Balbaert has been a lecturer in web programming and databases at CVO Antwerpen, a community college in Belgium. He received a Ph.D. in applied physics from the University of Antwerp in 1986. He worked for 20 years in the software industry as a developer and consultant in several companies, and for 10 years as project manager at the University Hospital of Antwerp. From 2000 onwards, he switched to partly teaching and partly developing software (at KHM Mechelen, CVO Antwerpen). He also wrote an introductory book in Dutch about developing in Ruby and Rails, Programmeren met Ruby en Rails, by Van Duuren Media. In 2012, he authored a book on the Go programming language, The Way To Go, by IUniverse. He wrote a number of introductory books for new programming languages, notably Dart, Julia, Rust, and Red, all published by Packt.

    Browse publications by this author

Latest Reviews

(3 reviews total)
see my previous remark, I don't want to rate every book seperately
Great content! Though I wish you'd get more C# titles
Excellent