Generic

Demo: generic-demo

Generic struct

// create a generic struct
struct Rectangle<T, U> {
    width: T,
    height: U,
}

// use it
let rect = Rectangle {
    width: 30,
    height: 50.0,
};

Generic method

impl<T, U> Rectangle<T, U> {
    fn get_width(&self) -> &T {
        &self.width
    }
}

print!("rect's width is {}", rect.get_width());

Since we don't know where the type T lives, stack or heap, it's safer to return a reference so that we can avoid transfering the ownship.

What's more, we can implement the methods for specific Rectangle.

impl Rectangle<f64, f64> {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

let rect_f64 = Rectangle {
    width: 30.0,
    height: 50.0,
};
println!("rect2's area is {}", rect_f64.area());

Generic function

fn get_bigger<T: PartialOrd>(first: T, second: T) -> T {
    if first > second {
        first
    } else {
        second
    }
}

println!("The bigger one is {}", get_bigger(10, 20));

<T: PartialOrd> makes sure the type T can be compared.

Box type

It stores the data on the heap instead of stack.

Box itself lives on the stack. It has a pointer which points to the data on the heap.

use std::mem;

let car = Shuttle {
    name: String::from("Car"),
    crew_size: 11,
    fuel: 1.0,
};
println!("The memory used on stack for a car: {} bytes", mem::size_of_val(&car));
// The memory used on stack for a car: 40 bytes

let boxed_car = Box::new(car);
println!("The memory used on stack for a boxed car: {} bytes", mem::size_of_val(&boxed_car));
// The memory used on stack for a boxed car: 8 bytes

println!("The memory used on heap for a boxed car: {} bytes", mem::size_of_val(&*boxed_car));
// The memory used on heap for a boxed car: 40 bytes

Smart pointer

The pointer kept by the Box has more functionality than reference.

Box<T> has the ownship to the data that it points to. That means once Box<T> is out of the scope, the data in heap is dropped.

println!("{}", boxed_car.crew_size); // OK. No problem.
println!("{}", car.crew_size);// Error, car lost its ownship. The ownership is transferred to boxed_car.

Use cases of Box

  • Store the type whose size can't be known at compile time, such as a recursive data type.

  • Move a large amount of data from stack to heap quickly.