Compound types combine multiple values into a single type. Rust has two primitive compound types: tuples and arrays.
Tuples have a fixed length and can contain different types.
fn main() {
let tup = (10, 1_234, 5678, 12.4, true, 'a');
let tup : (i32, i32, i32, f64, bool, char) = tup;
// Destruct tup through pattern matching
let (a, b, c, d, e, f) = tup;
println!("{}, {}, {}, {}, {}, {}", a, b, c, d, e, f);
// Destruct tup through indexing
let ten = tup.0;
let c = tup.5;
println!("{}, {}", ten, c);
// Return multiple values using a tuple
let s1 = String::from("Daltie");
let (s2, len) = find_length(s1);
println!("The length of '{}' is {}.", s2, len);
}
// Multiple values can be returned from a function using tuples
fn find_length(s: String) -> (String, usize) {
let length = s.len();
(s, length)
}
Arrays are of FIXED length and all elements must be of the same type. See vector in the standard library for a variable length container.
Array data is allocated on the stack rather than the heap (speedy!).
fn main() {
// Array Declaration
let a = [-1, 2, 3, 4, 5];
let a: [i32; 5] = [1, 2, 3, 4, 5]; // i32 is the type, 5 is the length
let a = [3; 5]; // [3, 3, 3, 3, 3]
// Indexing
let first = a[0];
let second = a[1];
// Out of Bounds Runtime error
let will_panic = a[12]; // Rust will panic and crash instead of trying to access invalid memory
}
If a function will never return use the never return type !
.
fn foo() -> ! {}
Some things that return the never type are continue
and panic!
.
Rust has four primary scalar types:
Length | Signed | Unsigned |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch* | isize | usize |
The "arch" length is system architecture dependent.
Number Literals | Example |
---|---|
Decimal | 12_345_678 |
Hex | 0xfe |
Octal | 0o76 |
Binary | 0b1111_0000 |
Byte (u8 only) | b'A' |
Length | Type |
---|---|
32-bit | f32 |
64-bit | f64 |
Note: Rust defaults all floats to f64
.
A boolean in Rust is either true
or false
and takes up one byte. The type is specified with bool
.
The character type in Rust is a four byte Unicode Scalar Value. For example:
fn main() {
let c = 'z';
let z = 'ℤ';
let laughing_crying_face = '😂';
}
A slice is a contiguous sequence of elements in a collection. The advantages of slices is they allow you to borrow part of a collection, such as a String or array. This is safe borrowing, if part of the original data is altered, the borrowed data is no longer valid.
fn main() {
let mut name = String::from("Daltie Cole");
let f_name = first_name(&name[..]); // Let first_name() borrow name. Pass as a string literal
//name.clear(); // Clear out the name
// If name was cleared, this line would not compile
println!("First name: {}", f_name);
// Other slicing fun
let daltie = &name[..7];
let cole = &name[8..];
let full_name = &name[..];
}
// By using &str as the parameter type instead of &String, string literals can be passed as well
fn first_name(name: &str) -> &str {
// Convert name into an array of bytes
let bytes = name.as_bytes();
// .iter() creates an iterator over the array
// .enumerate() wraps iter() into a series of tuples where
// the first element is the index and the second is the item
for (i, &item) in bytes.iter().enumerate() {
// If the element is a binary space
if item == b' ' {
// Return the slice from the beginning to the current point
return &name[0..i];
}
}
&name[..]
}
Returns true if a string contains a substring:
if s.contains("apple") {}
Iterate though each line in a string:
for line in s.lines() {}
Creates a new string containing the lowercase letters of the old string:
s.to_lowercase();
Use b""
to create a binary string.
The type
keyword is similar to typedef
in C++, a type becomes aliased as another type.
// Simple Example
type Meters = i32;
let x: i32 = 2;
let y: Meters = 5;
let z = x + y;
// Can be used with templates
type Result>T< = std::result::Result>T, std::io::Error<