"Unsafe" Rust is a subset of the Rust language that provides developers with low-level control over the memory and execution behavior of their programs. This subset of Rust allows them to bypass the safety guarantees provided by the language’s built-in safety features and access low-level functionality like accessing raw memory, creating null pointers or dereferencing uninitialized pointers, etc.
Developers should use "unsafe" Rust when they need to manipulate memory or access hardware, particularly when working with low-level systems programming. The use of "unsafe" Rust can often yield significant performance improvements compared to safe Rust, particularly when dealing with large or complex data structures.
A practical example of "unsafe" Rust can be seen in implementations of certain data structures such as linked lists or hash tables. In safe Rust, these data structures are implemented using safe, high-level abstractions that abstract away the details of memory management and pointer manipulation to provide a simplified interface to the developer. However, in some scenarios, this abstraction can get in the way, and implementing these data structures using "unsafe" Rust can result in better performance.
For example, the Rust standard library’s ‘Vec‘ data structure uses safe Rust to manage its allocation and deallocation of memory. However, if you need to build a custom data structure like a linked list where you require more fine-grained control over the allocation and deallocation of memory, you may need to use "unsafe" Rust.
Here is an example of an ‘unsafe‘ linked list implementation:
struct Node<T> {
value: T,
next: *mut Node<T>,
}
impl<T> Node<T> {
fn new(value: T) -> *mut Node<T> {
let node = Box::new(Node {
value: value,
next: std::ptr::null_mut(),
});
Box::into_raw(node)
}
unsafe fn append(&mut self, value: T) {
let mut node = self;
while !(*node).next.is_null() {
node = &mut *(*node).next;
}
(*node).next = Node::new(value);
}
}
Here, we create a ‘Node‘ struct that represents a single node in the linked list. The ‘new‘ function creates a new node and returns a raw pointer to it. We use the ‘*mut‘ type here to represent the raw pointer.
The ‘append‘ function appends a new node to the end of the linked list. We use the ‘unsafe‘ keyword here because we are accessing raw pointers and dereferencing them, which is not allowed in safe Rust.
Overall, "unsafe" Rust can be a powerful tool, but it should be used with caution. It should only be used when the performance gains outweigh the risks of bypassing Rust’s safety guarantees. Developers should always thoroughly test their "unsafe" code and be aware of the potential security vulnerabilities that can arise from its use.