Rust Quick Start Guide

5 (1 reviews total)
By Daniel Arbuckle
  • 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. Getting Ready

About this book

Rust is an emerging programming language applicable to areas such as embedded programming, network programming, system programming, and web development. This book will take you from the basics of Rust to a point where your code compiles and does what you intend it to do!

This book starts with an introduction to Rust and how to get set for programming, including the rustup and cargo tools for managing a Rust installation and development workflow.

Then you'll learn about the fundamentals of structuring a Rust program, such as functions, mutability, data structures, implementing behavior for types, and many more. You will also learn about concepts that Rust handles differently from most other languages.

After understanding the Basics of Rust programming, you will learn about the core ideas, such as variable ownership, scope, lifetime, and borrowing. After these key ideas, you will explore making decisions in Rust based on data types by learning about match and if let expressions. After that, you'll work with different data types in Rust, and learn about memory management and smart pointers.

Publication date:
October 2018
Publisher
Packt
Pages
180
ISBN
9781789616705

 

Chapter 1. Getting Ready

In this guide, we're going to learn the basics of working with Rust, a systems-level programming language that has been making a name for itself over the last few years. Rust is a strict language, designed to make the most common errors impossible and less common errors obvious.

Being a systems-level language means that Rust is guided by the needs of low-level programs that don't have a safety net, because they are the safety net for higher-level programs. Operating system kernels, web browsers, and other critical pieces of infrastructure are systems-level applications.

This is not to say that Rust can only be used for writing critical infrastructure, of course. The efficiency and reliability of Rust code can benefit any program. It's just that the priorities for higher-level code can be different.

In this chapter, we're going to cover the following topics:

  • The rustup tool
  • The cargo tool
  • How to start a new Rust project
  • How to compile a Rust project
  • How to locate third-party libraries
  • How to manage dependencies
  • How to keep a Rust installation up-to-date
  • How to switch between stable and beta Rust
 

Installing Rust


Installing Rust on any supported platform is simple. All we need to do is navigate to https://rustup.rs/. That page will give us a single-step procedure to install the command-line Rust compiler. The procedure differs slightly depending on the platform, but it's never difficult. Here we see the rustup.rs page for Linux:

The installer doesn't just install the Rust compiler, it also installs a tool called rustup that can be used at any time to upgrade our compiler to the latest version. To do this, all we have to do is open up a command-line (or Terminal) window, and type: rustup update.

Upgrading the compiler needs to be simple because the Rust project uses a six-week rapid release schedule, meaning there's a new version of the compiler every six weeks, like clockwork. Each release contains whatever new features have been deemed to be stable in the six weeks since the previous release, in addition to the features of previous releases.

Note

Don't worry, the rapid release of new features doesn't mean that those features were slapped together in the six weeks prior to the release. It's common for them to have spent years in development and testing prior to that. The release schedule just makes sure that, once a feature is deemed to be truly stable, it doesn't take long to get into our hands.

If we aren't willing to wait for a feature to be vetted and stabilized, for whatever reason, we can also use rustup to download, install, and update the beta or nightly releases of the compiler.

To download and install the beta compiler, we just need to type this: rustup toolchain install beta.

From that point on, when we use rustup to update our compiler, it will make sure that we have the newest versions of both the stable and beta compilers. We can then make the beta compiler active with rustup default beta.

Please note that the beta compiler is not the same thing as the next release of the stable compiler. The beta version is where features live before they graduate to stable, and features can and do remain in beta for years.

The nightly version is at most 24 hours behind the development code repository, which means that it might be broken in any number of ways. It's not particularly useful unless you're actually participating in the development of Rust itself. However, should you want to try it out, rustup can install and update it as well. You might also find yourself depending on a library that someone else has written that depends on features that only exist in the nightly build, in which case you'll need to tell rustup that you need the nightly build, too.

One of the things rustup will install is a tool called cargo, which we'll be seeing a lot of in this chapter, and using behind the scenes for the rest of this book. The cargo tool is the frontend to the whole Rust compiler system: it is used for creating new Rust project directories containing the initial boilerplate code for a program or library, for installing and managing dependencies, and for compiling Rust programs, among other things.

 

Starting a new project


Okay, so we've installed the compiler. Yay! But how do we use it?

The first step is to open up a command-line window, and navigate to the directory where we want to store our new project. Then we can create the skeleton of a new program with cargo new foo.

When we do this, cargo will create a new directory named foo and set up the skeletal program inside it.

The default is for cargo to create the skeleton of an executable program, but we can also tell it to set up a new library for us. All that takes is an additional command-line argument (bar is the name of the new directory that will be created, like foo): cargo new --lib bar.

When we look inside the newly created foo directory, we see a file called Cargo.toml and a sub-directory called src. There may also be a Git version control repository, which we will ignore for now.

Project metadata

The Cargo.toml file is where metadata about the program is stored. That includes the program's name, version number, and authors, but importantly it also has a section for dependencies. Editing the content of the [dependencies] section is how we tell Rust that our code should be linked to external libraries when it is compiled, which libraries and versions to use, and where to find them. External libraries are collections of source code that were packaged up in order to make them easy to use as components of other programs. By finding and linking good libraries, we can save the time and effort of writing our whole program ourselves. Instead, we can write only the part that nobody else has already done.

Note

By the way, .toml files are written in Tom's Obvious, Minimal Language (TOML), a more well-defined and feature-complete version of the old .ini format that Microsoft popularized but never standardized. TOML is becoming quite popular, and is supported and used in a wide variety of languages and applications. You can find the language specification at https://github.com/toml-lang/toml.

 

 

 

Dependencies on libraries from crates.io

If a library that our program depends on is published on https://crates.io/, all we have to do to link it is add its linking code to the dependencies section. Let's say we want to use serde (a tool for turning Rust data into formats such as JSON and back) in our program. First, we find its linking code with: cargo search serde.

Note

I originally found out about serde by browsing through crates.io, an exploration that I would encourage you to try as well.

This will print out a list of matches that looks something like this:

     serde = "1.0.70"                          # A generic serialization/deserialization framework
     serde_json = "1.0.24"                 # A JSON serialization file format
     serde_derive_internals = "0.23.1"     # AST representation used by Serde derive macros. Unstable.
     serde_any = "0.5.0"                   # Dynamic serialization and deserialization with the format chosen at runtime
     serde_yaml = "0.7.5"                 # YAML support for Serde
     serde_bytes = "0.10.4"              # Optimized handling of `&[u8]` and `Vec<u8>` for Serde
     serde_traitobject = "0.1.0"       # Serializable trait objects.  This library enables the serialization of trait objects such…
     cargo-ssearch = "0.1.2"             # cargo-ssearch: cargo search on steroids
     serde_codegen_internals = "0.14.2"    # AST representation used by Serde codegen. Unstable.
     serde_millis = "0.1.1"                #     A serde wrapper that stores integer millisecond value for timestamps     and duration…
     ... and 458 crates more (use --limit N to see more)

The first one is the core serde library, and the linking code is the part of the line before the # symbol. All we have to do is copy and paste that into the dependencies section of Cargo.toml, and Rust will know that it should compile and link serde when it compiles our foo program. So, the dependencies section of Cargo.toml would look like this:

 [dependencies]
 serde = "1.0.70"

 

 

 

 

Dependencies on Git repositories

Depending on a library stored in the Git version control system, either locally or remotely, is also easy. The linking code is slightly different, but it looks like this:

    [dependencies]
    thing = { git = "https://github.com/example/thing" }

We tell Rust where to find the repository, and it knows how to check it out, compile it, and link it with our program. The repository location doesn't have to be a URL; it can be any repository location that the git command recognizes.

Dependencies on local libraries

We can also link against other libraries stored on our own systems, of course. To do this, we just have to add an entry such as this to our Cargo.toml file:

     [dependencies]
     example = { path = "/path/to/example" }

The path can be absolute or relative. If it's relative, it's interpreted as being relative to the directory containing our Cargo.toml file.

Automatically generated source files

When creating an executable program, cargo adds a file called main.rs to our project as it is created. For a newly created library, it instead adds lib.rs. In either case, that file is the entry point for the whole project.

Let's take a look at the boilerplate main.rs file:

     fn main() {
         println!("Hello, world!");
     }

Simple enough, right? Cargo's default program is a Rust version of the classic hello world program, which has been re-implemented countless times by new programmers in every conceivable programming language.

If we look at a new library's lib.rs file, things are a little more interesting:

     #[cfg(test)]
     mod tests {
         #[test]
         fn it_works() {
             assert_eq!(2 + 2, 4);
         }
     }

Instead of having a main function, which all executable programs need because they need a place to start, the library boilerplate includes a framework for automated tests and a single test that confirms that 2 + 2 = 4.

 

Compiling our project


The basic command to compile a Rust program is simple: cargo build.

We need to be in the directory containing Cargo.toml (or any subdirectory of that directory) in order to be able to do this, since that's how the cargo program knows which project to compile. However, we don't need to give it any other information, since everything it needs to know is in the metadata file. 

Here, we see the result of building the chapter02 source code:

The warnings are expected and do not prevent the compile from succeeding. If we look at those warnings carefully, we can see that Rust is a lot more helpful with its warnings than many programming languages, giving us hints for improving efficiency and such, rather than just talking about language syntax.

When we build the program, a Cargo.lock file and target directory are created.

Cargo.lock records the exact versions of dependencies that were used to build the project, which makes it much easier to produce repeatable results from different compilations of the same program. It's largely safe to ignore this file, as cargo will usually take care of anything that needs to be done with it.

The Rust community recommends that the Cargo.lock file should be added to your version control system (Git, for example) if your project is a program, but not if your project is a library. That's because a program's Cargo.lock file stores all of the versions that resulted in a successful compile of a complete program, where a library's only encompasses part of the picture, and so can lead to more confusion than help when distributed to others.

The target directory contains all of the build artifacts and intermediate files resulting from the compilation process, as well as the final program file. Storing the intermediate files allows future compiles to process only those files that need to be processed, and so speeds up the compilation process.

Our program itself is in the target/debug/foo file (or target\debug\foo.exe on Windows) and we can navigate to it and run it manually if we want to. However, cargo provides a shortcut: cargo run.

We can use that command from any subdirectory of our project, and it will find and run our program for us.

Additionally, cargo run implies cargo build, meaning that if we've changed the source code since the last time we ran the program, cargo run will recompile the program before running it. That means we can just alternate between making changes to our code and executing it with cargo run to see it in action.

Debug and release builds

You may have noticed that the program was in a directory called target/debug. What's that about? By default, cargo builds our program in debug mode, which is what a programmer normally wants.

That means that the resulting program is instrumented to work with the rust-gdb debugging program so we can examine what is happening in its internals, and to provide useful information in crash dumps and such, as well as skipping the compiler's optimization phase. The optimizations are skipped because they rearrange things in such a way that it makes debugging information almost incomprehensible.

However, sometimes a program doesn't have any more bugs (that we know about) and we're ready to ship it out to others. To construct our final, optimized version of the program, we use cargo build --release.

This will construct the release version of the program, and leave it in target/release/foo. We can copy it from there and package it up for distribution.

 

 

Dynamic libraries, software distribution, and Rust

For the most part, Rust avoids using dynamic libraries. Instead, all of the dependencies of a Rust program are linked directly into the executable, and only select operating system libraries are dynamically linked. This makes Rust programs a little larger than you might expect, but a few megabytes are of no concern in the era of gigabytes. In exchange, Rust programs are very portable and immune to dynamically linked library version issues.

That means that, if a Rust program works at all, it's going to work on pretty much any computer running roughly the same operating system and architecture it was compiled for, with no hassles. You can take your release version of a Rust program, zip it up, and email it to someone else with confidence that they will have no problem running it.

This doesn't entirely eliminate external dependencies. If your program is a client, the server it connects to needs to be available, for example. However, it does greatly simplify the whole packaging and distribution process.

 

Using crates.io


We saw cargo search earlier, which allowed us a quick and easy way to find third-party libraries from the command line, so that we could link them with our own program. That's very useful, but sometimes we want a little more information than what that provides. It's really most useful when we know exactly which library we want and just need a quick reference to the linking code.

When we don't know exactly what we want, it's usually better to use a web browser to look around https://crates.io/ and find options.

When we find an interesting or useful library in the web browser, we get the following:

  • The linking code
  • Introductory information
  • Documentation
  • Popularity statistics
  • Version history
  • License information
  • A link to the library's web site
  • A link to the source code

 

This richer information is useful for figuring out which library or libraries are best suited to our projects. Picking the best libraries for the job saves a lot of time in the end, so the web interface to crates.io is great.

The front page of crates.io shows new and popular libraries, divided up in several ways, and these can be interesting and useful to explore. However, the main value is the search box. Using the search box, we can usually find several candidates for any library needs we may have.

 

Summary


So, now we know how to install the Rust compiler, set up a Rust project, find and link useful third-party libraries, and compile source code into a usable program. We've also taken a basic look at the boilerplate code that cargo generates when we ask it to set up a new program or library project for us. We've learned about the difference between a debugging build and a release build and taken a quick look at what's involved in distributing a Rust program to users.

Coming up in Chapter 2, Basics of the Rust Language, we're going to begin looking at the Rust programming language itself, rather than the support facilities that surround it. We're going to see how the language is structured and some of the most important commands.

About the Author

  • Daniel Arbuckle

    Daniel Arbuckle holds a Doctorate in Computer Science from the University of Southern California, where he specialized in robotics and was a member of the nanotechnology lab. He now has more than ten years behind him as a consultant, during which time he’s been using Python to help an assortment of businesses, from clothing manufacturers to crowdsourcing platforms. Python has been his primary development language since he was in High School. He’s also an award-winning teacher of programming and computer science.

    Browse publications by this author

Latest Reviews

(1 reviews total)
Great content in great formats

Recommended For You

Book Title
Access this book, plus 7,500 other titles for FREE
Access now