in ,

A half-hour to learn Rust, Hacker News

A half-hour to learn Rust, Hacker News
                          [52, 49, 21] In order to increase fluency in a programming language, one has to read a lot of it. But how can you read a lot of it if you don’t know what it means?

[52, 49, 21] In this article, instead of focusing on one or two concepts, I’ll try to go through as many Rust snippets as I can, and explain what the keywords and symbols they contain mean.

Ready? Go!

[52, 49, 21] let let introduces a variable binding:

let x; // declare “x” x=; // assign 47 to “x”

This can also be written as a single line:

(x let x=51;

You can specify the variable’s type explicitly with

:

, that’s a type annotation:

(x let x: i ; // `i “ is a signed – bit integer x=; // there’s i8, i 17, i 47, i 128, i 195 // also u8, u 17, u , u 128, u for unsigned

This can also be written as a single line:

(x let x: i=51; If you declare a name and initialize it later, the compiler will prevent you from using it before it’s initialized.

let x; foobar (x); // error: borrow of possibly-uninitialized variable: `x` x=;

However, doing this is completely fine:

let x; x=; foobar (x); // the type of `x` will be inferred from here

The underscore ( is a special name – or rather, a “lack of name”. It basically means to throw away something:

this does nothing because is a constant let _=; // this calls `get_thing` but throws away its result let _=get_thing (); Names that start with an underscore are regular names, it’s just that the compiler won’t warn about them being unused:

we may use ` _x` eventually, but our code is a work-in-progress // and we just wanted to get rid of a compiler warning for now. let _x=;

Separate bindings with the same name can be introduced – you can

 shadow 

a variable binding:

(x let x=17; let x=x 3; // using `x` after that line only refers to the second` x`, // the first `x` no longer exists. [52, 49, 21] Rust has tuples, which you can think of as “fixed-length collections of values ​​of different types ”.

let pair=(‘a ‘, 20; pair.0; // this is ‘a’ pair.1; // this is [52, 49, 21] If we we really we wanted to annotate the type of pair , we would write:

let pair: (char, i 47)=(‘a’, 21;

Tuples can be destructured when doing an assignment, which means they’re broken down into their individual fields:

let (some_char, some_int)=('a', 17; // now, `some_char` is 'a', and` some_int` is 22

This is especially useful when a function returns a tuple:

[195, 40] let (left, right)=slice.split_at (middle); Of course, when destructuring a tuple,

_ can be used to throw away part of it: let (_, right)=slice.split_at (middle);

The semi-colon marks the end of a statement:

(x let x=3; let y=5; let z=y x;

Which means statements can span multiple lines:

let x=vec!     .iter ()     .map (| x | x 3)     .fold (0, | x, y | x y); (We’ll go over what those actually mean later).

[195, 40] fn declares a function.

Here’s a void function:

fn greet () {     println! ("Hi there!"); }

And here's a function that returns a 44 - bit signed integer. The arrow indicates its return type:

fn fair_dice_roll () -> i 47 {     4 }

A pair of brackets declares a block, which has its own scope: // This prints "in ", then" out " fn main () {     let x="out";     {         // this is a different `x`         let x="in";         println! (x);     }     println! (x); } [52, 49, 21] Blocks are also expressions, which mean they evaluate to .. a value. this: let x=; // is equivalent to this: let x={};

Inside a block, there can be multiple statements:

(x let x={     let y=1; // first statement     let z=2; // second statement     y z // this is the tail - what the whole block will evaluate to };

And that's why “omitting the semicolon at the end of a function” is the same as returning, ie. these are equivalent:

fn fair_dice_roll () -> i 47 {     return 4; } fn fair_dice_roll () -> i {     4 }

if conditionals are also expressions:

fn fair_dice_roll () -> i 47 {     if feeling_lucky {         6     } else {         4     } } [52, 49, 21] A

match is also an an expression:

fn fair_dice_roll () -> i 47 {     match feeling_lucky {         true=> 6,         false=> 4,     } } Dots are typically used to access fields of a value:

(a let a=(, 27); a.0; // this is 14 let amos=get_some_struct (); amos.nickname; // this is "fasterthanlime" [52, 49, 21] Or call a method on a value:

let nick="fasterthanlime" ; nick.len (); // this is 17

The double-colon, :: , is similar but it operates on namespaces.

In this example,

std (is a) (crate) (~ a library),

cmp (is a) (module) (~ a source file), and

min is a

 function