-
Notifications
You must be signed in to change notification settings - Fork 0
Rust
Kevin Kredit edited this page Mar 24, 2020
·
6 revisions
Notes and lessons from the Rust programming language.
- Immutable by default
- Easily printable through formatting
traits, which optional formatting args for dec vs hex, e.g. - Array out-of-bounds fault is an compile-time error
- Constants my be declared in any scope, and have two types:
-
const: unchangeable value -
static: possibly mutable with a'staticlifetime; any use isunsafe
-
- Static
- Declared or inferred
- Literals can be type annotated
- Support for tuples
- Support for
traits, which are like typeclasses or interfaces - Lists:
- Array: collections of the same type; size known at compile time; signature
[T]; on stack - Slice: arrays, but size not known at compile time; comprised of a pointer and a length;
signature
&[T] - Vec: growable arrays allocated on the heap
- Array: collections of the same type; size known at compile time; signature
- Structs:
- Tuple structs (basically named tuples)
- "Classic C structs"
- Unit structs (empty, useful for generics)
- Enums:
- Creates a type that can be any type of struct, and even a mix! Kind of like a big
Either. See here
- Creates a type that can be any type of struct, and even a mix! Kind of like a big
- Type aliases:
type Alias = OldTypeName;- UpperCamelCase or produce a warning
- Do not provide type safety, as they're not new types
- Conversion is done using
traits -
!is the divergent type; it matches all other types, but indicates that something does not return
- Declared with
let; types declared or inferred - As mentioned in the data section, variables are immutable by default;
let mutdeclares mutable variables - Scoped to blocks,
{} - Shadowing is allowed
- Can shadow in a lower scope
- Can shadow in same scope by redeclaring with
let, which can also change types
- May be cast using
as; C-like conventions, except fully defined - Holes
_are allowed if you don't need to bind a variable
- Uses semicolons (sadly to me), but they have meaning
- Expression +
;= Statement (see here)- Variables are assigned from expressions
- Blocks are expressions
- Variables can be assigned from blocks if the last statement in the block is not suppressed with a semicolons
- Similarly, functions do not need an explicit return at the end, but can end with an expression
-
if/elseconditions don't need(), and are expressions--so can be used directly in assignments -
loop: infinite loops- Standard
breakandcontinue - Can also annotate loops with
'namesand break or continue from that named loop -
breakcan also "return" a value for the loop expression
- Standard
-
while: standard - Ranges can be built using
1..5;1..=5is inclusive -
foruses 3 types of iterator (let's usenamesas an example vector):-
names.iter(): borrows each element along the way;namesis still available for use after the loop -
names.into_iter(): consumes the collection;nameshas been "moved" -
names.iter_mut(): mutable version of.iter()
-
- Pattern matching using
match- Can be used like a C
switch - Can be used to de-structure tuples, enums, pointers, and structures
- Supports guards (yes!)
- Can bind the matched value using
@
- Can be used like a C
-
if let: lighter weight pattern matching often used to unwrapOptions and matchEnumtypes -
while let: while-version of if-let
- Highly capable macro system
- C-like, but considerably more powerful since it uses type information instead of pure string manipulation
- Macros defined using
macro_rules! macro_name {} - Examples here
-
returnis not mandatory; expressions == statements - Only one return value, but it can be a tuple
- Declared with
fn, signatures like `fn fn_name(var: type) -> returnType {} -
methodsare functions attached to objects; similar to Go; defined inimplblocks - Closures!
- Types inferred, var names must be specified
- Vars in
|var|, brackets{}necessary only if only one expression - Can have argument-less closures by
let closure = || expr; - Capture variables from enclosing scopes, so has borrowing implications
- Any function can be used as an argument; inside the receiving function, it is a closure
- Rust provides at least a few higher-order functions:
- Iterators can be lazy, giving a Haskell-ish feel (if not runtime behavior, thankfully)
-
map,filter,fold,take_while,for_each - See Rust's iter documentation
- Performance: they follow C++'s "zero overhead" principle (see here)
-
structobjects may havemethodsattached, creating Go-like interfaces; see functions section -
traitsare sets of methods than an object must implement in order to satisfy interfaces - Some traits can be derived
- Forced by type system with
Maybes -
unsafecode (see here)- Must put in
unsafe {}blocks - Limits scope of and makes explicit unsafe operations
- Operations include:
- dereferencing raw pointers
- calling functions or methods which are unsafe (including calling a function over FFI)
- accessing or modifying static mutable variables
- implementing unsafe traits
- Must put in
- Installation process is simple
- Compiler warnings and errors:
- Helpful, and has many sensible defaults (e.g. warnings for unused variables)
- Handy built-in conventions (e.g. no warnings for vars starting with
_) - Enforces (or tries to enforce) complete pattern matching
- Debugging
- Easy to setup by following this blog post
- Must build with
rustc -goption
Initial reaction: I expected to instantly find my next favorite language, but the syntax isn't very pretty.
Later reaction: Rust feels strong and safe. You can appreciate the modern features such as its
Maybes, its approach to objects and types, and its light functional capabilities, all while
appreciating its strong types, helpful compiler, and promises of memory safety. Parts of the syntax
are undoubtedly ugly, and in this time I have not completed the learning curve. However, syntax gets
uglier when you try to have an expressive language, and embedding complexity in the language itself
means you don't have to work around the language (c.f. waterbed
theory). I like Rust.