28 KiB
∈cludesvg[height=.25\textheight]{img/rust-logo-blk}≠wline An introduction to Rust
- Rust
- Abstract
- Strengths and Weaknesses1
- Strengths and Weaknesses2
- Problems Rust tries to conquer
- Where to start?
- Where to continue?
- Where to share, find help and stay up to date
- Language
- Statements vs. expressions
- Mutability and shadowing
- Tuple structs
- Structs
- Enums
- Pattern matching and some macros
if let
- Loops3
- Ownership
- References
- Lifetimes
- Error related types
- Error handling
- Printing
- Deriving
Debug
- Implementing
Display
- Use functional paradigms
- Tests
- Documentation
- FFI (Foreign Function Interface)
- Cargo
- Setup
- Common Crates
- Footnotes
Rust
Abstract
#+LaTeX:∈cludegraphics[width = 0.5\textwidth]{img/Bruine_roest_op_tarwe_(Puccinia_recondita_f.sp._tritici_on_Triticum_aestivum).jpg} 5
Rust, the language
- First public appearance 2010
- Rust is the coating closest to the bare metal
- Memory safe without gcing, optional reference counting
- Ownership, lifetimes, traits, functional paradigms, zero-cost and zero-size abstractions
- A well designed language and ecosystem
Strengths and Weaknesses1
Things Rust does measurably really well (Strengths)
- Compiled code about same performance as C / C++, and excellent memory and energy efficiency.
- Can avoid 70% of all safety issues present in C / C++, and most memory issues.
- Strong type system prevents data races, brings 'fearless concurrency' (amongst others).
- Seamless C interop, and dozens of supported platforms (based on LLVM).67
- "Most loved language" for 6 years in a row.
- Modern tooling:
cargo
(builds just work),clippy
(450+ code quality lints),rustup
(easy toolchain management).
Strengths and Weaknesses2
Points you might run into (Weaknesses)
- Steep learning curve8 compiler enforcing (esp. memory) rules that would be "best practices" elsewhere.
- Missing Rust-native libs in some domains, target platforms (esp. embedded), IDE features.8
- Longer compile times than "similar" code in other languages.89
- No formal language specification, can prevent legal use in some domains (aviation, medical, …).10
- Careless (use of
unsafe
in) libraries can secretly break safety guarantees.
Problems Rust tries to conquer
#+LaTeX:∈cludegraphics[width = 0.8\textwidth]{img/compiler_complaint.png} 11
- Dangling pointers / memory safety
- Iterator invalidation
- Thread safety / concurreny
- Segfaults
- Error handling
- Zero-cost and zero-size abstractions
Where to start?
First Steps
- Tour of Rust
- The Rust Book (
$ rustup docs --book
) - Rust in Easy English
- Rust by Example (
$ rustup docs --rust-by-example
) - The Rust Standard Library (
$ rustup docs --std
) - The Rustonomicon: The Art of unsafe Rust (
$ rustup docs --nomicon
) - Use '
$ rustup help docs
' to get an overview
Compact "cheat sheets"
Where to continue?
Further Steps
- Jon Gjengset (Considering Rust, Crust of Rust, Advanced topics in Rust)
Where to share, find help and stay up to date
Online sharing/testing
- play.rust-lang.org
- godbolt.org (Supports not only Rust)
Boards and Blogs
Language
- Semicolons have meaning (statements vs. expressions)
- Mutability
- Shadowing
- Memory safety
- Ownership, references and lifetimes
- Functional paradigms
- Pattern matching
- Metaprogramming (declarative and procedural macros)
- Meaningful compiler warnings and errors
Statements vs. expressions
Statements
let something = true;
fn_call();
Expressions
()
, false
, x + y
, fn_call()
, if
, match
Example
let bool_value = true;
let value = if bool_value {
"true".to_string()
} else {
"false".to_string()
};
Mutability and shadowing
Immutable variable
let foo = 5;
Mutable variable
let mut bar = 5;
bar = 6;
Shadowing
let baz = 5;
let baz = baz + 3;
Tuple structs
Definition of a tuple struct
struct Rectangle(usize, usize);
Instantiation of a tuple struct
let rect = Rectangle(3, 5);
Access of a tuple struct's field
rect.0;
rect.1;
Structs
- Direct access vs. getter and setter (
pub
keyword) Something::new(item)
andSomething::default()
Definition of a struct
struct Something {
id: usize,
item: String,
}
Enums
Enum example
enum Event {
Receive,
Send(String),
Reset { address: u64, hard: bool },
}
let new_event = Event::Send("A message".to_owned());
Pattern matching and some macros
All match arms must return the same type!!1!
Simple match
match an_enum {
MyEnum::Something => todo!("This has to be done"),
MyEnum::SmthngElse(_) => unimplemented!("This is unimplemented"),
MyEnum::AnotherThing(e) => println!("It is another thing: {}", e),
_ => unreachable!(),
};
Assigning match
let maturity = match age {
0 | 1 => "infant",
2..=12 => "child",
13..=19 => "teen",
_ => "...",
};
if let
Simpler match
if let Some(inner_value) = foo {
println!("Value: {}", inner_value);
} else {
println!("Nothing found");
}
Loops3
Loops
loop
: infinite loopswhile
: loops until a predicate is falsewhile let
: loops until a pattern is matchedfor
: loop over an iterator until it is empty
Loop labels
break
: terminate/exit a loopcontinue
: exit the current iteration and jump to the loop header
Ownership
Ownership is one of Rusts central concepts to achieve memory safety without garbage collection.
Ownership Rules
- Each value has a variable that is called its owner.
- There can only be one owner at a time.
- When the owner goes out of scope, the value will be dropped.
References
- A value can temporarily borrowed from its owner without transferring ownership.
- There can be multiple immutable references.
- There can only be one mutable reference.
- The
&
symbol is the reference operator. - The
*
symbol is the dereference operator. - References are immutable by default, use the
mut
keyword to make them mutable.
Lifetimes
- The Rust compiler (borrow checker) keeps track of how long references (borrows) are valid.
- To ensure valid borrows and therefor prevent dangling borrows Lifetimes are used.
- Lifetimes are annotations which tell the borrow checker how long a borrow needs to be valid.
- Lifetimes are implicit and inferred, that means the compiler infers lifetimes wherever possible.
- Lifetimes must be annotated when the borrow checker cannot infer them on its own.
Struct with lifetimes
struct SomeApp<'a> {
config: &'a Config,
}
Error related types
- Heavy use of
Option<T>
andResult<T, E>
Option
pub enum Option<T> {
None,
Some(T),
}
Result
pub enum Result<T, E> {
Ok(T),
Err(E),
}
Error handling
Unrecoverable errors → panics
fn get_data() -> Data {
...
panic!("Cannot get data");
}
Recoverable error with anyhow
fn get_data() -> Result<Data> {
...
Ok(data) // return is only used for "early" returns
}
...
let data = get_data()?;
...
Printing
When printing something, {}
uses the std::fmt::Display
trait
and {:?}
uses the std::fmt::Debug
trait.
print!()
and println!()
let amount = 3;
let fields = vec![0,2,5];
println!("We have {} of {:?}", amount, fields);
Prints: We have 3 of [0, 2, 5]
Deriving Debug
To enable printing of structs or enums when their fields implement
Debug
they can be derived with following annotation.
Deriving Debug
#[derive(Debug)]
struct Something {
id: usize,
item: String,
}
Implementing Display
Implementing Display
use std::fmt;
struct Something {
id: usize,
item: String,
}
impl fmt::Display for Something {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.id, self.item)
}
}
Use functional paradigms
vec![1, 2, 3].iter()
vec![1, 2, 3].iter().sum()
vec![1, 2, 3].iter().map(|x| x + 1).collect()
foo.into_iter().filter(|i| i.bar == 0).collect()
Iterator
trait
Tests
- Use
assert!()
family -
Unit tests
- Put them into a test module
- Annotate the test module with
#[cfg(test)]
- Annotate the tests with
#[test]
- Documentation testing
-
Integration testing
- Integration tests are put into the
src/tests/
directory
- Integration tests are put into the
- Rust Book: Writing Automated Tests
- Alastair Reid: Rust Design-for-Testability: a survey
Documentation
- Documentation comments:
///
- Markdown notation
cargo doc
runns rustdoc which generates html docscargo doc --open
runs rustdoc and opens the result in a browser- rustdoc documentation
FFI (Foreign Function Interface)
- Rustonomicon: FFI
- jni: Java bindings for Rust
- Calling Rust From Python
- Rustler: Write Erlang NIFs in Rust
Cargo
Cargo
\Huge Cargo
What is it and how does it work?
- Package manager
- Build chain/tool
- Cargo calls
rustc
, the Rust compiler - A Cargo project contains at least one crate
- Custom build scripts with
build.rs
- Builds just work
Cargo commands
Create a new binary crate (init
does so in an existing directory)
$ cargo new [--bin] <PATH>
Create a new library crate (init
does so in an existing directory)
$ cargo new --lib <PATH>
Update build dependencies
$ cargo update
Install crates
$ cargo install [crate]
Hello, World
Executing `cargo new foobar`
creates a new project…
foobar/Cargo.toml
[package]
name = "foo"
version = "0.1.0"
authors = ["finga <finga@onders.org>"]
edition = "2018"
\tiny
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
\normalsize
[dependencies]
foobar/src/main.rs
fn main() {
println!("Hello, world!");
}
Docs
- Cargo help:
$ cargo --help
and$ cargo [SUBCOMMAND] --help
- The Cargo Book (
$ rustup docs --cargo
) - Guillaume Gomez: Guide on how to write documentation for a Rust crate
- Policies
- Category Slugs
Cargo commands/plugins
What I typically use
audit
: AuditCargo.lock
for security vulnerabilities.bloat
: Identify which dependency adds how much bloat.checkmate
: Run a list of checks (check
,format
,build
,test
,doc
,audit
).clippy
: Linter and static code analysis.deb
: Automatically create a Debian package.flamegraph
: Generate flamegraphs about anything.fmt
: Format Rust code according to style guidelines.install-update
: Keep all your Cargo commands/plugins up to date.
Cargo downloads your Rust package's dependencies, compiles your package, makes distributable packages, and is able to upload them to crates.io, the Rust community's package registry.
Setup
Setup
\Huge
How to get all that stuff?
Install the Rust-Toolchain
Install the Rust toolchain (rustup.rs
)
$ curl --proto '=https' --tlsv1.2 -sSf \
https://sh.rustup.rs | sh
Rustup: The Rust toolchain installer
- Check for new versions:
$ rustup check
- Update the toolchain:
$ rustup update
- Update rustup itself:
$ rustup self update
- Install Rust nightly (daily builds):
$ rustup toolchain install nightly
- Activate nightly globally:
$ rustup default nightly
- Activate nightly locally (in current dir):
$ rustup override set nightly
IDE support aka are we IDE yet?4
\tiny
\rotatebox{90}{Syntax highlightning (.rs)} | \rotatebox{90}{Syntax highlightning (.toml)} | \rotatebox{90}{Snippets} | \rotatebox{90}{Code Completion} | \rotatebox{90}{Linting} | \rotatebox{90}{Code Formatting} | \rotatebox{90}{Go-to Definiton} | \rotatebox{90}{Debugging} | \rotatebox{90}{Documentation Tooltips} | |
---|---|---|---|---|---|---|---|---|---|
Atom | X | X | X | X | X | X | X | X | |
Emacs | X | X | X | X | X | X | X | X | |
Sublime | X | X | X | X | X | X | X | ||
Vim/Neovim | X | X | X | X | X | X | X | X | |
VS Code | X | X | X | X | X | X | X | X | X |
BBedit | X | X | X | X | X | ||||
Geany | X | ||||||||
gedit | X | X | X | ||||||
Kakoune | X | X | X | X | X | X | X | X | |
Kate | X | X | X | X | X | X | |||
Micro | X | X | X | X | |||||
Midnight Commander | X | ||||||||
Textadept | X | X | X | X | X | X | |||
Eclipse | X | X | X | X | X | X | X | X | |
IntelliJ-based IDEs | X | X | X | X | X | X | X | X | X |
Visual Studio | X | X | X | X | |||||
GNOME Builder | X | X | X | X | X | X | |||
Ride | X |
Common Crates
General
General
Misc. Crates
- dotenv
- tokio
Parsing/Encoding
Error handling
- anyhow
- thiserror
- snafu
- easy-error
- eyre
- color-eyre
Logging
- log: a lightweight logging facade
- env_logger
- simple_logger
- simplelog
- pretty_env_logger
- stderrlog
- flexi_logger
- log4rs
- fern
- and many many more (checkout the log readme12)
Testing
- quickcheck
- proptest
- rutenspitz
- cargo-fuzz
- afl.rs
- honggfuzz-rs
- arbitrary
Data handling
- lazy_static
- once_cell (globality, singleton, lazy initialization)
- static_assertions
- GhostCell
Tui
- rustyline: Line editing library
- tui: Library for ncurses like things
- crossterm: Cross-platform terminal manipulation library
Gui (areweguiyet.com)
WebDev
Unikernel
For general information about unikernels visit unikernel.org.
Thats it for now
\Large
Thank you for your attention!
Questions?
\normalsize
To be continued
Column left
- Traits
- Generics
- Type Aliases vs. New Type Idioms
- Ownership
- References and Slices
- Lifetimes
- Iterators
- Functional paradigms
Column right
- Metaprogramming (macros)
- (Smart) Pointers
- Concurrency
- Object Oriented Programming
- Closures
- Async-Await
unsafe
Rust
Footnotes
Work on GCC: rust-gcc and gcc rust backend.