I first came across Rust through a project named Servo. Rust was born out of an attempt to rewrite the rendering engine behind Firefox. Since then it has been voted the “most loved language” at least two years in a row (see Stack Overflow Developer Survey 2017).
The best way to learn Rust is by reading the second edition of the official book. I purchased a copy of the book and the following are notes I took while reading the book or other resources.
One of the first things you’ll notice immediately is that
println
is a macro, not a function. More generally, this is
how metaprogramming is done in Rust. For example, if you would like to
write a routine that takes a variable number of arguments or has default
values you’ll need to write a macro.
Another important bit of syntax is the semicolon, which terminates an expression. The value of the final expression in the block of the body of a function is the return value.
Cargo can be used to create a project, build the code, download and
manage dependencies. This becomes increasingly important because the
standard library in Rust is relatively small. When creating a project
use --bin
to specify building a application. Cargo will
initialize a git repository by default. It manages dependencies for a
project by generating a Cargo.lock
file.
std::prelud
const
, named with all caps/underscores, always annotated
with a type, and are always immutablelet
statement::
in String::new()
indicates that
new
is an associated function, which is like a static
methodnew()
is just a convention&
to indicate a reference, but
it is much safer and easier to useResult
is another convention that can be found
throughout the standard library. It is an enumeration, which consists of
variantscargo doc --open
will generate documentation for all of
your dependencies and open them in your browsermatch
expression is made up of arms that consist of a
pattern and the code that should be run if the value matches.char
type can represent a broad range of Unicode
scalar values, which doesn’t necessarily match intuition of what a
character isf64
_
as a visual separatorfmt::Debug
/{:?}
and
fmt::Display
/{}
are available for anything in
the standard library. Otherwise add #[derive(Debug)]
to the
line before a definition. fmt::Display
needs to be manually
implementedx = y = 6
, which would assign
6
to both x
and y
in C{}
creates a new scope and is also
an expression because it may return a value. This is also true of
if
statements! Note that when assigning the return value of
a if
statement to a variable it must be followed by a
else
statement otherwise the return value is ambiguous if
the first conditional is false.Copy
trait, while nothing
that requires allocation or is some form of resource doesstr
manages an immutable pointer to memory, while
String
handles allocating and deallocating memory when
expanding to shrinking the size of a string. It can be thought of as
String
holding a str
. It is not possible to
create a str
explicitly although it is the type returned by
slices and string literals. A str
is often used as a
&str
, which is borrowed from a String// A string literal is simply an immutable String reference
let sl = "Hello world";
// Create a String from a string literal
let s = String::from("Hello world");
let mut msr = &s[..];
or
let mut msr = &"Hello world"[..];
clear()
the String.struct
can be used when initializing a struct
instance. This is
primarily helpful in functions where the parameters match the field
names. This is known as field init shorthand.struct Person {
: String
name}
let name = String::from("John");
{name}; Person
struct
update syntax allows creating a new instance of
a struct
based on a current instance, while changing some
fields. The final line in the block includes ..
followed
immediately by the name of the current instance.struct
s allow you to define a struct
without field names if you want two struct
s to have the
same members but different typesstruct
s don’t have any fields and behave like
the unit type, which is what is returned by expressions that don’t
return anythingstruct
that takes
&mut self
as a parameter, the instance also needs to be
mutable. If self
is a parameter then the method takes
ownership of the object, which may be used to transform the object. A
method that does not take self
as a parameter is referred
to as an associated function, which is called using the
struct
name and ::
.struct
each variant of an enum
may
store data (e.g. no data, anonymous struct
,
String
, tuple). Also, a enum
may define
methods.enum Option<t> { Some(T), None, }
, which is included
in the prelude as well as it’s variantsif let
is a nice alternative to match
for
more concise code, but less checkingmod.rs
, which is in turn inside a directory with the same
name as the modulemod {}
or as a file
module-name.rs
, which can then be included using
mod module-name
.pub
), it can be accessed
through any of its parent modules, however if it is private then it can
only be accessed by its immediate parent module and any of the parent’s
child modulesuse
(e.g. use a::nested::module
). Bring an enum
s
variants into scope using {}
(e.g. use AdditivePrimaries::{Red, Green};
) or glob
(e.g. use AdditivePrimaries::*;
). Access a parent using
relative to the root using ::a::nested::module
or using
super::module
let v: Vec<u64>
), the compiler an infer it.
For more convenience use the vec!
macro
(e.g. let v: = vec![1, 2, 3];
)[]
(e.g. &v[2]
) will panic!
if an element at
that index does not exist. Alternatively, use .get()
, which
returns a Option<&T>
.*
to get the underlying
valuepush_str()
will add the reference to another String, but I
would think that it does a copy if the original String is mutable? We
already have a mutable reference and then we try to take an immutable
one?HashMap
s are a bit cumbersome and not as well
supporteduse std::collections::HashMap;
let teams = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.iter().zip(initial_scores.iter()).collect();
static mut
variables that are similar
to globals, but their use must be in a unsafe function or block