Rust datatypes: Difference between revisions

From wikinotes
Line 322: Line 322:
</syntaxhighlight>
</syntaxhighlight>


You can also store complex information in a struct
You can also store complex information in an enum, making it more struct-like
<syntaxhighlight lang="rust">
<syntaxhighlight lang="rust">
enum Event {
enum Event {

Revision as of 20:17, 7 February 2023

Documentation

primitives https://doc.rust-lang.org/std/#primitives

Literals

General

'a'        // char
"abc"      // string (immutable)
1234       // i32
3.14       // f32
true/false // bool

Numeric Representations

1_000      // == 1000
1.000_000  // == 1.000000

0xff          // hex
Oo644         // octal
0b1111_0000   // binary
b'A'          // byte (u8)

Type Suffixes

1u8          // '1' as a u8
1i64         // '1' as a i64

Primitives

Text

str

  • immutable
  • size-known at compile-time

https://doc.rust-lang.org/std/primitive.str.html

let name: &str = "vaderd";     // assign string
let mut user = String::new();  // utf8 string

// type casting 'string' to 'i8'
let num: i8 = "123"
  .parse()
  .unwrap();

Some Useful Methods

"abc".len()            // 3  number of bytes used
"abc".ends_with("bc")  // true if ends with

char

chars refer to a single character, and it's literals use single-quotes.
chars use 4-bytes in memory; they can store multibyte characters.

https://doc.rust-lang.org/std/primitive.char.html

let foo: char = 'a';

String

String types are strings with a string-size that is unknown at compile-time.

let mut mystr = String::from("foo")
mystr.push("bar!");  // foobar!

Numbers

implied type let var = 12;
assigned type let var: i8 = 12;
type suffix let var = 12i8;

int

  • signed integers range is split in two, can be positive/negative
  • unsigned integers are positive, and use all available bits
  • use radix to calculate max size that can be accomodated with b bits
// signed integers, by bit-size
i8     //        -128..127
i16    //      -32768..32767
i32    // -2147483648..2147483647
i64    // ...
i128
isize  // your CPU wordsize (ex. i32 or i64)

// unsigned integers, by bit-size
u8    // 0..255
u16   // 0..65535
u36   // 0..4294967295
u64   // ...
u128 
usize // your CPU wordsize (ex. u32 or u64)

float

f32
f64

bool

true
false

fn foo(b: bool) { ... }

Collections

tuples

  • heterogenous
  • non-resizable
  • not stored in contiguous memory
  • support nesting

https://doc.rust-lang.org/std/primitive.tuple.html#

let var: (i8, char, u32) = (5, 'a', 300);
var = (1, "two", 3.14)
var.0  // item at index 1

arrays

  • homogenous
  • non-resizable
  • stored in contiguous memory

https://doc.rust-lang.org/std/primitive.array.html

// initialization
let var: [i32; 4] = [1, 2, 3, 4];  // declare an array of 4x 32-bit integers
let var: [i32; 4] = [100; 4];      // initialize all 4x ints as 100

// methods
var[0]     // 1
var.len()  // 4

// slices
let foo = &var[1..2];   // [2, 3]
println!("{}", foo[0]); // 2

slices

slices are a subsection of an array

let var: [i8; 4] = [1, 2, 3, 4];

let first_two = &var[0..1];   // [1, 2]
let first_two = &var[..1];    // [1, 2]
println!("{}", foo[0]); // 2

fn foo(s: &[i32]) { ... }               // borrows slice of an i32 array
fn foo(s: String) -> &str { ... }       // returns slice of String
fn foo(nums: &[usize; 10]) -> &[usize]  // returns slice of array (slice indexes always usize)

vectors

vectors are essentially resizable arrays.

  • homogenous
  • resizable
  • stored in contiguous memory

https://doc.rust-lang.org/std/vec/index.html

let v: Vec<i32> = Vec::new();
let v = vec![1, 2, 3, 4, 5];

structs

Struct is either entirely mutable, or entirely immutable.
You cannot make some fields mutable and others not.

Structs can contain references to objects owned by others.

Regular Structs

struct Point { x: u8, y: u8 }
let p: Point = Point { x: 5, y: 10 };  // assignment
println!("point({}, {})", p.x, p.y);   // access fields with '.'

Structs have syntactic sugar so that you can reuse parameters for assignment.

struct Coord { x: u8, y: u8, z: u8 };
fn build_coord_at_x0(x: u8, y: u8) {
    Coord{
        x: 0,
        y,
        z
    }  // bind `y`, `z` values from matching params
}

There is also syntactic sugar for creating a struct from another of the same type,
only replacing select values.

struct Coord { x: u8, y: u8, z: u8 };

let p1 = Coord{x: 1, y: 2, z: 3};
let p2 = Coord{x: 5, ..p1};         // reuse fields from `p1` for all values except `x`

Tuple Structs

struct Color(i8, i8, i8);             // declaration
let c: Color = Color(100, 150, 200);  // instantiation
c.1 = 200;                            // assignment (uses `.` index)

Unit Structs

Unit structs have no value, they're just a type.

struct Centimeters;
let cm = Centimeters;

General

TODO:

not sure this really belongs here..

Debug trait

#[derive(Debug)]
struct Point{x: i8, y: i8}
let p = Point{x: 1, y: 2};

println!("{:?}", p);  // print all fields on struct
println!("{:#?}", p); // pretty-print struct
dbg!(p)               // prints the file, lineno, expression, and result

Pointers

Pointers

Function Pointers

References

Other

Enums

enum TaskStatus {
  Blocked,
  Ready,
  Started,
  Finished,
}

TaskStatus::Ready

You can also store complex information in an enum, making it more struct-like

enum Event {
  KeyPress(char),            // like tuple-struct
  Click { x: i32, y: i32 },  // like c-structs
  Blue = 0x0000ff,           // assign value
}

Event::KeyPress('j')

Scoping with use

use TaskStatus::*;
let foo = Blocked;

use TaskStatus::{Blocked, Ready};
let foo = Blocked;
let bar = Started;  // raises error, since not in scope

Result

Results are chainable enums with success/failure values.