










Warning
If someone is reading this blog, please be aware that the writer did not consider the experience of the other readers.
After all, the most important part is about writing things down for better memorization.
There’s actually no ownership design in C, which means that the language, or more specifically the compiler, does not check anything about ownership, leaving the burden to the programmers.
For example, look at the declaration of the function below:
1 |
|
Just from the doc comment for this function, you can tell that the memory management process is like messy. Programmers should be cautious when invoking those functions, carefully reading doc comment for each one to understand the ownership implications.
Not only that, the memory area pointed to by the pointer taken as a parameter in this function cannot be freed with free(), there’s a specific function called dvb_frontend_detach responsible for destroying that heap-allocated memory.
Even worse, the data structure pointed by the pointer might need multiple different functions to free the memory allocated earlier. This can be very complicated and prone to mistakes, leading to memory corruption or memory leak.
Rust addresses this problem with a unique concept: ownership.
Ownership is Rust’s most unique feature and has deep implications for the rest of the language. It enables Rust to make memory safety guarantees without needing a garbage collector, so it’s important to understand how ownership works.
Three ownership rules:
1 | fn log(s: String) { |
The code above won’t compile. Reason is that the first time we invoke log on s, the function takes the ownership of the string so the second time we call it, s no longer owns the string "hello" anymore.
In other words, the memory that stores the string "hello" would have been freed after the first call to log(s).
Here we can see that Rust is trying to make sure that every value is not NULL or None when they are used, in a very strict way. Any manipulation(i.e., borrowing) of the value is treated with caution; hence, the value is often not allowed after such an operation.
In C, where the allocation and deallocation of the memory is controlled manually by the programmer, you can free the buffer s anywhere in the code. Either after the first time calling log, or the second time, or even inside the log function(right after printing the string to the standard output). This seems manageable in a simple example like the one above, but you can’t make that promise anymore when the complexity of the code grows. (Reality has proven this.)
1 | void log(char *s) { |
1 | fn main() { |
This code compiles without error. & stands for borrowing (i.e., referencing), which does not tranfer the ownership from its original owner.
However if we change one of the references to a mutable reference, like the way down below:
1 | let s1 = &mut s; |
Then it won’t compile. This introduces another rule about borrowing:
The purpose of this rule is easy to understand: You don’t want the data you’re reading to change unexpectedly. So Rust enforces that only one entity may mutate a value at a time, and during mutation, no other entity may read or write to it. But it’s okay that more than one guy reading from the same value, as long as none of them is modifying it.
TODO
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。