Getting Started with Rust: An Introduction to Cargo

Two toddlers wearing headphones playing with colored blocks on a tab

Hopefully, at this point, you've got Rust installed and you're good to go. If you haven't, just pop on over here.

We want to start things off by having you get to know your way around Cargo. Cargo is Rust's build system and package manager. Now, there's no real Ruby build system. As we discussed earlier, Ruby is an interpreted language and is translated to machine code every time we do a ruby hello_world.rb.

A package manager, we're actually used to having. We have RubyGems, and the Rust equivalent to a gem is a crate. Cargo is going to let us manage crates and dependencies very similarly to how we've been using RubyGems and Bundler in the past. We are not going to get into the nitty gritty details of Cargo, but we will cover enough to get you up and running. If you want to know more about Cargo, the internet is your oyster.

So let's get started. So we should use Cargo to start new Rust projects. Now, we can simply just create a file with the .rs file extension, but let's use Cargo. It'll give us some structure.

$ cargo new hello_world

This should look familiar to you. Essentially how you'd start a Rails app. What's happened here is that we've created a new directory and a project called hello_world.  When we enter the directory with a cd hello_world we see this file structure:

We have the following:
 * A src directory with a file in it called main.rs. The src directory is the equivalent to the Ruby lib directory and the main.rs file is where your code goes.
 * We have a .gitignore too. Cargo has taken the liberty of intializing a git repository for us in addition to the .gitignore. If you are not a git person you can override this with a command line argument to the cargo new.
 * Finally we have a Cargo.toml file.

Let's talk about that Cargo.toml file. Well, it's written in TOML, Tom's Obvious, Minimal Language. Because yes, we need to learn yet ANOTHER text format, in addition to YAML, Markdown, and whatever other format that the tool you started using yesterday forced you to learn. If you want to learn more about TOML, have at it. Don't get me wrong, I am absolutely sure that there's a VERY  good reason behind the choice of TOML, and to be honest, a standard is certainly better than another DSL to learn, but what was the problem with YAML? Who hurt you?

If we open the Cargo.toml file this is what we'll see:

[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"

[dependencies]

This is what gets generated for you with a cargo new.  This file holds all of the configuration information and dependencies for this project in particular. It is essentially your Gemfile. Here, we can see that it is split into two sections with headers in the square brackets.

The [package] section contains configuration information that Cargo will need to compile your program. Specifically the name of your project, the version of the project and which edition of Rust to use. New editions can be considered major version changes in the language of semantic versioning.  cargo new will always default to using the latest stable edition.

And the [dependencies] section. This is where you addin crates that you may need. Works just the same way that we add gems in our Gemfile in Ruby.

We have one last file to look at, the code generated. Let's take a look at the main.rs in the src directory.

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

This is code that is generated whenever we use Cargo to create a new project. There is absolutely no artificial intelligence going on here where Cargo sees that we named the project hello_world so the default code is going to print out Hello, world! to our terminal. This code would be identical if we had simply run the following in our terminal:

$ cargo new poopy_mcpooperson

If we look at this file, we can see that it's not quite what we're used to . With Ruby, we start with an empty file. Here, we have what looks like a JavaScript function with some code within that looks like it'll print out Hello, World! to our terminal.

With Rust, we have to compile our code before we run it. And so when we compile our code and run it, what happens is that it'll grab the code in the main.rs file and the main function in there, and that's what gets executed first. It's a little different from Ruby in that when we are working in Ruby, whatever is in the file gets executed.

It helps me understand what's going on by thinking that in Ruby, we do have a sort of a main method that gets automatically run when we execute a file. However, because Ruby likes to be human friendly and not make us worry about a lot of things, the existence of that main method or function is implied. We kind of just operate as if it was there, even though it's not. Rust works in more of an explicit way in that it makes us use a main function.

So we have some code how do we compile and run it? Well, we can compile our code with cargo build. This will create a new file in target/debug/ with the same name as the project. So to run it you would run this following command:

$ ./target/debug/hello_world

On a windows machine you would run

.\target\debug\hello_world.exe

This is annoying, so cargo lets us combine the two actions like so:

$ cargo run

This syntax is great because it will indeed compile your code and run, but if you have previously compiled your code and performed another cargo run it is smart enough to detect that there are no changes, and just run your executable without compiling your code again.

The final important cargo command you should know is cargo check. This will run through your code and let you know if there's any errors or problems that would stop your code from compiling before you compile. This is useful but I don't actually use this feature at al. I'm a vim user at heart but I'm most productive with VS Code, and Rust has great tooling with that editor and will tell me when I've messed up. I have yet to build something on the larger side yet, so cargo check may still be a tool I use in the future, but right now I'm doing pretty well.

Anyhow, this was a basic rundown of how to use cargo and how it fits in with programming in Rust.

Subscribe to Rust for Rubyists

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe