Starting Rust From A Scripting Background
Follow Along: http://rust-from-a-scripting-background.readthedocs.org/en/latest/
Follow Along: http://rust-from-a-scripting-background.readthedocs.org/en/latest/
You:
What you can't get from the book:
Note
Rust is an extremely feature-rich language and introductions are usually taught in 1-2 full days of workshops. The best we can do in 1 hour is build your interest and motivation, and make sure you know what questions to ask as you get involved.
Note
Let's make sure we're all on the same page about some stuff you might never have needed to think about before.
tl;dr, computers are dumb but compilers are smart.
https://people.cs.clemson.edu/~mark/uprog.html is a neat overview of very low-level stuff.
RAM is quick to access but impermanent
Disk is slower to access but more permanent
Stack & Heap are abstractions for how a program manages its own memory
(https://en.wikipedia.org/wiki/Data_segment#/media/File:Typical_computer_data_memory_arrangement.png)
Plus some optimizations
To write smaller and faster programs, you have to think harder about exactly what the CPU is doing.
Compiled:
Interpreted:
Note
Choose a compiled language when:
- Speed/performance is essential
- Can't afford runtime crashes
- Targeting an embedded platform with ~0 storage/memory
Choose an interpreted lanaguage when:
- You're more fluent in it and need the code done fast
- Code performance isn't essential
- Some cases of targeting multiple platforms
Systems programming: (assembly, C, C++, Rust)
Applications programming: (Python, Ruby, Java)
Note
Systems programming prioritizes speed and performance, and traditionally has expected programmers to memorize all the rules for how not to make mistakes.
(https://en.wikipedia.org/wiki/LAMP_%28software_bundle%29#/media/File:LAMP_software_bundle.svg)
Note
Systems code (ie kernel, drivers, etc) is pretty much all C today.
Other languages
Safe Rust:
Note
If you're just getting started and targeting a normal platform (or want to add support for your obscure favorite), Rust is like an automated mentor
If you're contributing to an existing code base in another language or hunting a job at a C++-only shop, the things you learn from Rust will improve your code, but it might not be your best choice
Note
http://graydon2.dreamwidth.org/218040.html is a list of common systems programming "footguns" absent from Rust
Applications programming languages
Other systems languages:
Safe Rust:
Note
Imagine that it's possible to enumerate every valid program (valid = free from memory mismanagement bugs, use-after-free errors, array out of bounds, etc.). The set of programs which the Rust borrow checker accepts is slightly smaller, but guaranteed to be contained within, the set of all valid programs.
What happens when you want to write code that you can prove is valid, but the borrow checker won't accept? Use the unsafe keyword to take down the metaphorical guard rails for a small section of code.
When you're starting out, try to write only safe Rust. In cases where you must use unsafe, be sure to understand why.
Note
Now we're on the same page about the basic concepts of systems programming, let's take a high-level look at some things you'll need to know about Rust to start using it
"The stable release channel will provide pain-free upgrades, and the nightly channel will give early adopters access to unfinished features as we work on them."
Just want to try it out?
Need one version, with Cargo?
Need several versions?
$ cargo new myproject
OR
$ multirust run stable cargo new myproject
THEN
$ vim myproject/src/lib.rs
http://doc.rust-lang.org/stable/book/
https://github.com/carols10cents/rustlings
https://github.com/ctjhoa/rust-learning
Note
This part is basically section 4 of The Book (http://doc.rust-lang.org/stable/book/syntax-and-semantics.html) but skipping as much as possible.
// Main takes no arguments and returns nothing
fn main(){
// The function body is the *scope* inside these curly braces
// Create a variable. It owns a string.
let what_to_say = "Hello World";
// Meet print syntax
println!("This program says {}", what_to_say);
}
http://rustbyexample.com/primitives/literals.html
Note
basic_syntax.rs http://rustbyexample.com/primitives/literals.html
4.1. Variable Bindings 4.2. Functions 4.3. Primitive Types 4.4. Comments 4.32. Operators
fn not_main(){
let what_to_say = "Hello World";
}
fn main(){
println!("This program says {}", what_to_say);
}
<anon>:5:42: 5:53 error: unresolved name `what_to_say` [E0425]
<anon>:5 println!("This program says {}", what_to_say);
^~~~~~~~~~~
<std macros>:2:25: 2:56 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std
macros>)
<anon>:5:9: 5:55 note: in this expansion of println! (defined in <std macros>)
<anon>:5:42: 5:53 help: see the detailed explanation for E0425
error: aborting due to previous error
fn main(){
let what_to_say = "Hello World"
println!("This program says {}", what_to_say);
}
<anon>:6:9: 6:16 error: expected one of `.`, `;`, or an operator, found `println`
<anon>:6 println!("This program says {}", what_to_say);
^~~~~~~
fn main(){
let what_to_say = "Hello World"
println!("Hello");
}
<anon>:4:13: 4:24 warning: unused variable: `what_to_say`,
#[warn(unused_variables)] on by default
<anon>:4 let what_to_say = "Hello World";
^~~~~~~~~~~
fn main(){let what_to_say="Hello World";println!
("This program says {}",what_to_say);}
fn
main
(
)
{
let what_to_say
=
"Hello World"
;
println
! (
"This program says {}"
, what_to_say
) ; }
Note
The only whitespace which matters is that which separates tokens.
fnmain
is different from fn main
. Other than that, the compiler
doesn't enforce any rules, though you can use
https://github.com/manishearth/rust-clippy and
https://github.com/rust-lang-nursery/rustfmt for formatting and style
guidance
Note
Have you ever been using a language without a strong type system, and returned a string from a function where you were expecting to get an int out? Rust forbids those bugs.
char: Unicode scalar values, like 'a', 'α' and '∞' (4 bytes each)
bool: either true or false
arrays, like [1, 2, 3]
tuples, like (1, true)
http://rustbyexample.com/primitives.html
Things each type can do are in standard library docs, like http://doc.rust-lang.org/stable/std/primitive.bool.html
Note
Here we're skipping book sections...
- 4.11. Structs
- 4.12. Enums
- 4.16. Vectors
- 4.17. Strings
http://doc.rust-lang.org/stable/book/functions.html
return
or bare final expression->
tells the typefn and(x: bool, y: bool) -> bool{
x && y
}
fn another_and(x: bool, y: bool) -> bool{
return x && y;
}
fn main() {
println!("{}", and(true, false));
println!("{}", another_and(true, false));
}
Note
function_and_operator.rs
4.15. Method Syntax 4.24. Universal Function Call Syntax
fn and(x: bool, y: bool) -> bool{
x && y;
}
...
<anon>:1:5: 3:6 error: not all control paths return a value [E0269]
<anon>:1 fn and(x: bool, y: bool) -> bool{
<anon>:2 x && y;
<anon>:3 }
<anon>:1:5: 3:6 help: see the detailed explanation for E0269
<anon>:2:15: 2:16 help: consider removing this semicolon:
<anon>:2 x && y;
^
error: aborting due to previous error
fn and(x: bool, y: bool) -> bool{
return 3;
}
...
<anon>:2:15: 2:16 error: mismatched types:
expected `bool`,
found `_`
(expected bool,
found integral variable) [E0308]
<anon>:2 return 3;
^
<anon>:2:15: 2:16 help: see the detailed explanation for E0308
fn and(x: bool, y: bool) -> i32{
if x && y {
return 3;
}
return 0;
}
fn and(x: bool, y: bool) -> i32{
if x && y {
return 3;
}
// what if we don't do anything here?
}
<anon>:2:9: 4:10 error: mismatched types:
expected `i32`,
found `()`
(expected i32,
found ()) [E0308]
<anon>:2 if x && y {
<anon>:3 return 3;
<anon>:4 }
...
fn main() {
let number = 13;
// TODO ^ Try different values for `number`
println!("Tell me about {}", number);
match number {
// Match a single value
1 => println!("One!"),
// Match several values
2 | 3 | 5 | 7 | 11 => println!("This is a prime"),
// Match an inclusive range
13...19 => println!("A teen"),
// Handle the rest of cases
_ => println!("Ain't special"),
}
}
fn main() {
let boolean = true;
// Match is an expression too
let binary = match boolean {
// The arms of a match must cover all the possible values
false => 0,
true => 1,
// TODO ^ Try commenting out one of these arms
};
println!("{} -> {}", boolean, binary);
}
fn main() {
// `n` will take the values: 1, 2, ..., 100 in each iteration
for n in 1..101 {
if n % 15 == 0 {
println!("fizzbuzz");
} else if n % 3 == 0 {
println!("fizz");
} else if n % 5 == 0 {
println!("buzz");
} else {
println!("{}", n);
}
}
}
http://rustbyexample.com/flow_control/for.html
Note
4.5. if 4.6. Loops 4.13. Match 4.14. Patterns 4.21. if let
fn main() {
// `n` will take the values: 1, 2, ..., 100 in each iteration
for n in 1..101 {
...
}
println!{"{}", n}
}
<anon>:14:24: 14:25 error: unresolved name `n` [E0425]
<anon>:14 println!{"{}", n}
^
<std macros>:2:25: 2:56 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std
macros>)
<anon>:14:9: 14:26 note: in this expansion of println! (defined in <std
macros>)
<anon>:14:24: 14:25 help: see the detailed explanation for E0425
http://doc.rust-lang.org/stable/book/ownership.html
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
First, any borrow must last for a scope no greater than that of the owner.
Second, you may have one or the other of these two kinds of borrows, but not both at the same time:
- one or more references (&T) to a resource,
- exactly one mutable reference (&mut T).
(http://doc.rust-lang.org/stable/book/references-and-borrowing.html)
What if we broke those rules?
fn borrow_int(borrowed_int: &i32) {
println!("I borrowed the int {}", borrowed_int);
}
fn main() {
let my_int : i32 = 42;
borrow_int(&my_int);
println!("I still have my int. it's {}.", my_int)
}
http://rustbyexample.com/scope/borrow.html
Note
(~10mins)
4.7. Ownership 4.8. References and Borrowing 4.9. Lifetimes 4.26.const and static 4.10. Mutability
fn main() {
let immutable_int = 42;
println!("immutable_int contains {}", immutable_int);
let mut mutable_int = immutable_int; // this makes a copy
println!("mutable_int contains {}", mutable_int);
println!("immutable_int contains {}", immutable_int);
mutable_int = 5;
println!("mutable_int now contains {}", mutable_int);
}
immutable_int contains 42
mutable_int contains 42
immutable_int contains 42
mutable_int now contains 5
metadata.
fn main() {
let immutable = "I'm immutable!".to_string();
println!("immutable contains {}", immutable);
let mut mutable = immutable; //move the value, not copy
println!("mutable contains {}", mutable);
mutable = "I have been mutated".to_string();
println!("mutable now contains {}", mutable);
}
immutable_string contains I'm immutable!
mutable_string contains I'm immutable!
mutable_string now contains I have been mutated
fn main() {
let immutable = "I'm immutable!".to_string();
let mut mutable = immutable; //move the value, not copy
println!("immutable contains {}", immutable);
}
<anon>:5:43: 5:52 error: use of moved value: `immutable` [E0382]
<anon>:5 println!("immutable contains {}", immutable);
^~~~~~~~~
...
<anon>:5:43: 5:52 help: see the detailed explanation for E0382
<anon>:4:13: 4:24 note: `immutable` moved here because it has type
`collections::string::String`, which is moved by default
<anon>:4 let mut mutable = immutable; //move the value, not copy
^~~~~~~~~~~
Note
http://rust-from-a-scripting-background.readthedocs.org/en/latest/
Set up Rust
Join us on IRC (#rust on irc.mozilla.org)