That is, learning from C99.
- by default variables are constant. To make a variable mutable, it has to have the
mutkeyword:- otherwise it would not compile
fn main() {
// also, type inferrence
let mut foo = 'A';
foo = 'b';
}- duplicate variable definitions get marked merely as unused variables:
fn main() {
let foo = 1;
let foo = 3;
}- The exclamation mark means this is a macro.
- for printing there is also
print!andeprint!andeprintln!(for stderr)
- for printing there is also
fn main() {
println!("Hello, world!");
}- print macros have interpolation:
fn main() {
let foo = "bar";
println!("{}", foo);
println!("{foo}"); // since some Rust version
}- the ability to use expressions within the
{}seems to be limited (unlike in Python)
fn main() {
let signs = "QRYZEPTGMk ";
println!("{signs.len()}"); // fails to compile
println!("{}", signs.len());
}- no semicolon at the end of a function means the value should be returned
- in such case, the
unitprimitive type marked()is returned
- in such case, the
fn main() {
// there does not have to a semicolon for the last expression/statement in a block/function
let x = println!("{}", 'A'.is_ascii_hexdigit())
}- there is 128-bit integer type:
fn main() {
let mut foo:u128 = 2 << 68;
while foo > 0 {
// also, string interpolation
println!("{foo}");
foo = foo / 8;
}
}- the compiler itself detects overflow (unlike C which leads to floating point HW exception):
let a: i8 = -128;
println!("{}", a / -1); // causes compile error: attempt to compute `i8::MIN / -1_i8`, which would overflowWhen println!("{}", a / "-1".parse::<i8>().unwrap()); is used, it causes the "attempt to divide with overflow" panic.
The unwrap() call takes the actual result of the parse() operation, if there is one, otherwise panics.
The panic happens only when compiling with dev mode according to https://doc.rust-lang.org/stable/book/ch03-02-data-types.html
For release builds the overflow happens.
- accessing a slice beyond outside index results in panic (due to the bound check):
fn main() {
let signs = " TGMK";
// also note that slice cannot be used directly on str (&signs[8]) cause of UTF-8
let letter = &signs.as_bytes()[8];
}- sliced
str(string type) has to be dereferenced and casted to get a printable char:
fn main() {
let signs = "TGMK ";
let letter = &signs.as_bytes()[0];
println!("letter '{}'", *letter as char);
}statically typed language - the types of all variables have to known at compile time.
rust makes a point about data living on the stack vs. on the heap.
- fixed size; there is no such thing as VLAs (although there is a crate that implements it however has some unsafe corners)
- if dynamic array is needed, use the vector (
Vec, allocated on the heap)
- if dynamic array is needed, use the vector (
- runtime enforces array boundaries - out of bounds access causes panic
- boundless case:
let a = ["foo", "bar"] - case of array with type specification:
let a: [i32; 5] = [1, 2, 3, 4, 5];- no way to specify lower dimension than the number of items in the initializer (so that the unspecified items can be initialized e.g. to 0)
- also no way to specify dimension without type it seems (in which case the above will become array of
u128)
- initialize the array with repetition of given value using semicolon:
let a = [3; 42](3 values, each equal to 42)
-
rustcis the low-level compiler utility,cargois the high-level (make/dependencies)cargo run,cargo build,cargo clean
-
there is no macro language per se like in C, however portions of code can be compiled based on flags
# Cargo.toml
[features]
my_feature = [] #[cfg(feature = "my_feature")]
{
println!("count = {count}");
print!("{foo} ");
}https://doc.rust-lang.org/cargo/reference/cargo-targets.html#target-auto-discovery
The directory structure allows e.g. for compilation of multiple binaries. src/bin/{foo,bar}.rs will build 2 programs
in the target directory after running cargo build.
Used this for my Advent Of Code solutions.