The unsafe
keyword allows you to create a block of code where some of Rust's safety guarantees are no longer applied. This is sometimes necessary when Rust is being to conservative.
Use cases:
union
sIt is the programmer's responsibility to make sure the code in a unsafe
block is safe.
unsafe fn unsafe_func() {} // Call unsafe inside of here, user beware! Read the docs!
fn abstraction() {} // Unsafe is inside this function, but we are smarter than
// the compiler (maybe) so we know that the contents of the function are fine
// All functions called from a different programming language are unsafe
extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
unsafe_func();
}
abstraction();
unsafe {
println!("Abs(-12) = {}", abs(-12));
}
}
Unsafe rust has two raw pointer types:
*const T
*mut T
Raw pointers:
fn main() {
let mut num = 4;
// Raw pointers can be created in safe mode
let rp1 = &num as *const i32; // *const i32 is the type
let rp2 = &mut num as *mut i32; // *mut i32 is the type
// Deallocating raw pointers can only be done in unsafe mode
unsafe {
//*rp1 = 10; // Does not work because *const
println!("*rp1 = {}", *rp1);
*rp2 = 12;
println!("*rp2 = {}", *rp2);
}
}
Rust static variables are called global variables in other languages.
static PI: f32 = 3.14159;
static mut COUNTER: u32 = 0;
fn main() {
// Accessing non-mutable static variables is safe
println!("Pi = {}", PI);
unsafe {
// Accessing mutable static variables is unsafe (think threads)
COUNTER += 1;
}
}
Traits are unsafe when at least one of its methods have some invariant that the compiler cannot verify. For example, using structs consisting of raw pointers for multi-threaded purposes. We'd have to mark the Send
and Sync
traits for our struct as unsafe
since Rust cannot verify the struct's safety.
unsafe trait Apple {}
unsafe impl Apple for i32 {}