raw pointer
Raw pointers in Rust are similar to pointers in C. They allow for manual, direct manipulation of memory. There are two types of raw pointers in Rust:
-
*const T
, which is an immutable raw pointer (you can’t modify the data it points to). -
*mut T
, which is a mutable raw pointer (you can modify the data it points to).
Here’s an example of raw pointers:
let mut x = 5;
let raw = &mut x as *mut i32;
let points_at = unsafe { *raw };
println!("raw points at {}", points_at);
In the above example, raw
is a mutable raw pointer that points to the memory location of x
. unsafe
is required to dereference raw pointers (with *raw
), because the compiler cannot guarantee that the memory location is valid, not freed, not null, and properly aligned.
Remember, it’s very rare that you’ll need to use raw pointers in everyday Rust programming. The majority of the time, Rust’s safe pointers (references) are more than sufficient. Raw pointers are used when you need to interface with foreign code (like C libraries), when you need to share memory between threads (concurrency), or when doing complex memory manipulations (like writing your own data structures).
unsafe
The unsafe
keyword in Rust indicates that the programmer explicitly knows what they’re doing, understands the potential risks involved, and accepts any consequences. In unsafe
blocks, Rust relaxes some of its guarantees, allowing the programmer to perform actions that might be allowed in other languages like C++. Here are some of the actions that can be performed within an unsafe
block:
-
Dereference raw pointers: Rust only allows the use of safe references in normal code, which are non-null and guaranteed not to cause data races. However,
unsafe
in Rust allows you to create and dereference raw pointers. -
Call unsafe functions or methods: Some Rust functions or methods are marked as
unsafe
, indicating they do something the compiler can’t verify as safe. To call these functions or methods, you need to do so within anunsafe
block. -
Access or modify mutable static variables: Rust’s static variables are similar to global variables in other languages. Accessing or modifying mutable static variables needs to be done within an
unsafe
block. -
Implement unsafe traits: Some traits are marked as
unsafe
, indicating that any type implementing this trait needs to uphold certain invariants. Implementing these traits needs to be done within anunsafe
block.
The unsafe
keyword should be used with caution. Although unsafe
allows you to bypass some of Rust’s checks, improper use can lead to memory safety issues or data races. In most cases, you should try to avoid using unsafe
, and only use it when absolutely necessary. Furthermore, you should try to encapsulate unsafe
code within safe APIs to minimize the potential damage of unsafe
code.
And here are the examples for each scenario:
- Dereferencing a raw pointer:
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
In the code above, we first create two raw pointers r1
and r2
, and then dereference them in an unsafe
block. Note that although creating raw pointers is safe, dereferencing raw pointers is unsafe.
- Calling an unsafe function or method:
unsafe fn dangerous() {}
unsafe {
dangerous();
}
In the code above, we define an unsafe function dangerous
and then call it in an unsafe
block.
- Accessing or modifying mutable static variables:
static mut COUNTER: u32 = 0;
fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
In the code above, we define a mutable static variable COUNTER
and then modify it in a function with an unsafe
block.
- Implementing unsafe traits:
unsafe trait Foo {}
unsafe impl Foo for i32 {}
Note: In Rust, unsafe impl Foo for i32 {}
means that you are providing an implementation of an unsafe trait named Foo
for the type i32
.
Traits in Rust are a way to define behavior that types should have. They are similar to interfaces in languages like Java. An “implementation” of a trait for a type, or impl
in short, is where you provide the actual code for that behavior.
When you see unsafe
before impl
, it means that the trait being implemented (Foo
in this case) is marked as unsafe
. This signifies that implementing the trait involves some invariant (a condition always true in correct usage) that the compiler can’t check.
For example, suppose we have the following unsafe trait:
unsafe trait UnsafeTrait {
fn dangerous_operation(&self);
}
This trait might represent some operations that are potentially unsafe and can’t be checked by the compiler. To implement this trait for a type, we use unsafe impl
:
unsafe impl UnsafeTrait for i32 {
fn dangerous_operation(&self) {
// some potentially unsafe operation here
}
}
In this example, we’re promising that our implementation of dangerous_operation
for i32
adheres to the requirements that UnsafeTrait
specifies (but which the compiler can’t verify).
As always, the unsafe
keyword in Rust is a signal that extra care needs to be taken. It’s a way of saying “I, the programmer, have checked this carefully and it is correct, even though the compiler can’t check it for me.”文章来源:https://www.toymoban.com/news/detail-626339.html
These are just some basic examples of unsafe
usage. The scope of unsafe
is far more extensive, and it can be used for tasks like building and interfacing with FFI (Foreign Function Interface). However, bear in mind that while unsafe
lets you bypass some of Rust’s checks, misuse can lead to memory safety issues or data races. In most cases, you should try to avoid using unsafe
, and only use it when absolutely necessary.文章来源地址https://www.toymoban.com/news/detail-626339.html
到了这里,关于Rust- unsafe的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!