Making Your First Rust App

Clap
0|0|

Getting started#

We are going to build an application in Rust to get a feel for the language and ecosystem. The first step for all new Rust projects is generating a new project. Let's create a new project called numbers:

Cargo is the package manager for Rust. It is used as a command line tool to manage dependencies, compile your code, and make packages for distribution. Running cargo new project_name by default is equivalent to cargo new project_name --bin which generates a binary project. Alternatively, we could have run cargo new project_name --lib to generate a library project.

Binary vs. library#

A binary project is one which compiles into an executable file. For binary projects, you can execute cargo run at the root of your application to compile and run the executable.

A library project is one which compiles into an artifact which is shareable and can be used as a dependency in other projects. Running cargo run in a library project will produce an error as cargo cannot figure out what executable you want it to run (because one does not exist). Instead, you would run cargo build to build the library.

There are different formats which the Rust compiler can generate based on your configuration settings depending on how you wish to use your library.

The default is to generate an rlib which is a format for use in other Rust projects. This allows your library to have a reduced size for further distribution to other Rust projects while still being able to rely on the standard library and maintain enough information to allow the Rust compiler to type check and link to your code.

Alternative library formats exist for more specialized purposes. For example, the cdylib format is useful for when you want to produce a dynamic library which can be linked with C code. This produces a .so, .dylib, or .dll depending on the target architecture you build for.

The generated project#

Let's enter the directory for our newly generated Rust project to see what is created:

The generated structure is:

Rust code organization relies primarily on convention which can be overridden via configuration, but for most use cases the conventions are what you want.

main.rs#

For a binary project, the entry point is assumed to be located at src/main.rs. Furthermore, inside that file, the Rust compiler looks for a function named main which will be executed when the binary is run. Cargo has generated a main.rs file which contains a simple "Hello, world!" application:

The syntax here says define a function (fn) with the name main which takes zero arguments and returns the empty tuple ().

Leaving off the return type is equivalent to writing -> () after the argument list of the function. All function calls are expressions which must return a value. The empty tuple () is a marker for no value, which is what a function with no return type implicitly returns.

The body of the function calls a macro println which prints its argument "Hello, world!" to standard out followed by a newline.

We will cover macros more later, but for now we will mention a few basics. We know it is a macro invocation and not a normal function call because of the trailing ! in the name. Macros are a powerful form of meta-programming in Rust which you will use frequently but probably rarely find the occasion to have to write. Rust implements println as a macro instead of as a regular function because macros can take a variable number of arguments, while a regular function cannot.

The syntax of Rust is superficially similar to C++ which we can see as curly braces are used for denoting blocks and statements are semicolon terminated. However, there is quite a bit more to the Rust grammar that we will cover as we go along.

Cargo.toml#

The Cargo.toml file is the manifest file for the project which uses the TOML format. This is the entry point for describing your project as well as specifying dependencies and configuration. The initial generated file contains the bare essentials for describing your project:

The blank section for dependencies is included because nearly every project includes some dependencies. One feature of Rust has been to keep the core language and standard library relatively slim and defer a lot of extra functionality to the community. Therefore relying on third party dependencies is encouraged.

Crates#

The primary unit of code organization in Rust is called a crate. Your code exists as a crate which can be distributed to the community via crates.io. Crates in Rust are analogous to gems in Ruby or packages in JavaScript. The registry at crates.io is similar to rubygems.org or npmjs.com as the de facto community repository for distributing and sharing code.

Binary Rust projects are also called crates so they do not solely represent shared library code. Furthermore, a crate can contain both a library and an executable.

It is often difficult to foresee how other's will want to use your software. A common practice in the Rust community is to create dual library/binary crates even when the primary intention of a project is to produce an executable. This can have positive effects on the API design of your code knowing that it should be suitable for external consumption. The binary part of the crate is typically responsible for argument parsing and configuration, and then calls into the functionality exposed by the library part of the crate. Writing all of your code only as an executable and then trying to extract a library after the fact can be a more difficult process. Moreover, the cost of splitting code into a library is minimal.

Clap
0|0
 

This page is a preview of Fullstack Rust

No discussions yet. Be the first. All notification go to the author.