Skip to content

Latest commit

 

History

History
340 lines (233 loc) · 7.99 KB

TEXT.md

File metadata and controls

340 lines (233 loc) · 7.99 KB

a-very-brief-intro-to-rust


links

PRs and issues welcome!

made by @ag_dubs who is, at best, an advanced beginner in Rust


This guide is an intro to Rust syntax. It doesn't touch on concepts at all.

Concepts are more important, but sometimes you need a little boost to get to a point where the concepts make sense.

This is that boost.


install rust

The best way to install Rust is with rustup. rustup is a Rust version manager. To install it type:

curl https://sh.rustup.rs -sSf | sh

To keep your rust up-to-date with the latest stable version of rust, type:

rustup update

To check which version of Rust you have type:

rustc --version

setting up a project

There are many ways to setup a project in Rust, but this is the simplest.

  1. Create a repository on Github
  2. Clone the repository
  3. cd into the repository directory
  4. Type cargo init .
  • Use --bin if you are not writing a library

This will create several files and folders for you automatically:

  • Cargo.toml: metadata about your project and its dependencies
  • .gitignore: ignores compiled files built by Rust
  • src/lib.rs or src/main.rs: where your Rust code goes

setting up a project

lib.rs vs main.rs

There are 2 main types of projects you can make in Rust: a library and not a library.

If you are writing a library, it means you intend for your code to be used in someone else's application as a crate or module. If you want to do this, you should use a lib.rs.

If you are writing a not library, it means that you'd like to write code that compiles into a binary that someone can run. If you want to do this, you need to use a main.rs. Inside the main.rs you should have a main function that looks like this:

fn main() {
  // your app code goes here
}

cargo

Cargo is a tool that helps you develop Rust. It does several things:

  • Runs tasks: cargo build (compile your app), cargo test (test your app), cargo run (run your app)
  • Start a project: cargo new, cargo init

Cargo is also the package manager for Rust. This means that you can use Cargo to install and manage bits of other people's code.

  • A package in Rust is called a Crate.
  • You can find Crates on http://crates.io
  • You list the Crates you want to use in the Cargo.toml file
  • Your app keeps track of what crates you are using in the Cargo.lock file

storing values

To get started using Rust you'll probably want to assign values so that you can use them. To do this in Rust:

let name = "ashley";
let age = 30;

If you want to make a constant, you must specify a type:

const FAVENUM: u32 = 6;

types

There are a lot of types, but just to get you started:

  • u32: unsigned 32-bit integer
  • i32: signed 32-bit integer
  • String and/or &str: more on these below
  • bool: a boolean

dealing with strings

Strings in Rust are a lot more complicated than you might be used to if you are coming from another language, in particular, interpreted languages like Ruby or JavaScript. Here's some key points:

&str and String

  • "my string" is not a String. it's a str. the difference between a String and a str is how they are allocated. Don't worry about that right now.
  • pretty much always use str with an &, as &str.
  • You can turn a &str into a String by using to_string() or String::from(). You want to do this because String has a ton of awesome convenience methods.

concatenation

  • add a &str to a String using push_str()
let mut realstring = String::from("hello ");
let str1 = "world!";
realstring.push_str(str1);
  • add &strs using format!
let str1 = "hello ";
let str2 = "world!";
let message = format!("{}{}", str1, str2);

characters

  • a char is a different type than a str or String. char always uses single quotes.
  • to get a String's chars you can call chars()
  • you might find that instead of chars() you really want as_bytes() but if you aren't sure don't sweat it right now.

Example:

let name = String::from("ashley");
let letters = name.chars();

for l in letters {
  // do something cool with characters
}

macros

Macros are an interesting part of Rust. You know something is a macro if its name has a !. The least technical way to describe the cool thing about macros is that they kinda get compiled twice. Don't worry if that doesn't make any sense.

  • println! is the equivalent of console.log or puts. It prints printable things to standard output, which is usually just the console.
println!("i get printed on the screen");
println!("hello {}!", "world");
  • format! is also a macro. We talked about it before as a way to concatenate strs.
format!("my dogs are named: {} and {}", "cheeto", "frito");

function signatures

pub fn say_hello(name: &str) -> String {
  let message = format!("hello, {}!", name);
  message
}
  • put pub at the beginning if you want the function to be accessible outside the file as in a module or crate
  • the keyword fn is how we know it is a function
  • list parameters inside the parens in the style parameter_name: Type, separate by commas
  • use the -> to say what type the function returns
  • return a value from the last line of a function by omitting the semicolon
  • return early in a function using the return keyword

match syntax

Rust has pattern matching and it's great!

match animal {
  "cat" => "Meow",
  "dog" => "Woof",
  _ => "<indecipherable>", // trailing comma!
}
  • _ is used as a catch-all for anything that doesn't match
  • match supports trailing commas, and it's best practice to use them :)

the Option type

Rust doesn't have nil/null so if you want to express that something might return something or nothing, you need to use the Option type.

To write the Option type, write the word Option, followed by angle brackets with a Type inside, e.g. Option<u32>.

For example, if a parameter is optional you'd write:

fn greeting(name: Option<&str>) -> String {
  let who = match name {
    Some(n) => n,
    None => "World",
  };
  format!("Hello, {}!", who)
}
greeting(Some("ashley"));
// "Hello, ashley!"
greeting(None);
// "Hello, World!"

the Result type

Result is kind of like Option except instead of something or nothing, you expect something that is Ok (Ok()) or an error (Err()).

To write the Result type, write the word Result, follow by angle brackets with a Type and an Error Type inside, e.g. Result<u32, &'static str>. For example:

fn parse_name(name: Option<&str>) -> Result<&str, &'static str> {
  match name {
    Some(n) => Ok(n),
    None => Err("You must provide a name."),
  }
}

testing

Rust has unit testing built in! You can write tests in their own file or right inline with your code.

To designate a test write #[test] above a code block with asserts:

fn say_hello(name: &str) -> String {
  let who = match name {
    Some(n) => n,
    None => "World",
  };
  format!("Hello, {}!", who)
}

#[test]
fn it_should_say_hello() {
  assert_eq!(say_hello(None), String::from("Hello, World!"));
  assert_eq!(say_hello(Some("World")), String::from("Hello, World!"));
  assert_eq!(say_hello(Some("ashley")), String::from(("Hello, ashley!"));
}

good resources


go forth and write some Rust!