引用
引用
堆栈,堆和指针在
- 堆栈非常快,但是堆却没有那么快。
- 堆栈需要在编译时知道变量的大小。因此,像
i32 这样的简单变量就会进入堆栈,因为我们知道它们的确切大小。 - 有些类型在编译时不知道大小。但是堆栈需要知道确切的大小。你是做什么?您将数据放入堆中,因为堆可以具有任何大小的数据。为了找到它,将指针放在堆栈上,因为我们一直都知道指针的大小。
指针就像书中的目录:
MY BOOK
Chapter Page
Chapter 1: My life 1
Chapter 2: My cat 15
Chapter 3: My job 23
Chapter 4: My family 30
Chapter 5: Future plans 43
您通常在let my_variable = 8
做一个常规变量,但是 let my_reference = &my_variable
会创建一个引用。这意味着 my_reference
仅查看 my_variable
的数据,my_variable
仍然拥有其数据。
Reference
fn main() {
let country = String::from("Austria");
let ref_one = &country;
let ref_two = &country;
println!("{}", ref_one);
}
country
是
fn main() {
let country = return_str();
}
fn return_str() -> &str {
let country = String::from("Austria");
let country_ref = &country;
country_ref // ⚠️
}
函数 return_str()
创建一个字符串,然后创建对该字符串的引用。然后,它尝试返回引用。但是 country
只存在于函数内部。因此,函数结束后,country_ref
指的是已经消失的内存。
反引用与点运算符
我们了解到,当您有参考时,需要使用 *
来获取值。引用是另一种类型,因此无法使用:
fn main() {
let my_number = 9;
let reference = &my_number;
println!("{}", my_number == reference); // ⚠️
}
error[E0277]: can't compare `{integer}` with `&{integer}`
--> src\main.rs:5:30
|
5 | println!("{}", my_number == reference);
| ^^ no implementation for `{integer} == &{integer}`
我们将第println!("{}", my_number == *reference);
就可以了,这也就是所谓的.
称为点运算符。
struct Item {
number: u8,
}
fn main() {
let item = Item {
number: 8,
};
let reference_number = &item.number; // reference number type is &u8
println!("{}", reference_number == 8); // ⚠️ &u8 and u8 cannot be compared
}
点运算符
为了使其工作,我们需要取消引用:println!("{}", *reference_number == 8);
,但是使用点运算符,我们不需要 *
。例如:
struct Item {
number: u8,
}
fn main() {
let item = Item {
number: 8,
};
let reference_item = &item;
println!("{}", reference_item.number == 8); // we don't need to write *reference_item.number
}
现在让我们为*
:
struct Item {
number: u8,
}
impl Item {
fn compare_number(&self, other_number: u8) { // takes a reference to self
println!("Are {} and {} equal? {}", self.number, other_number, self.number == other_number);
// We don't need to write *self.number
}
}
fn main() {
let item = Item {
number: 8,
};
let reference_item = &item; // This is type &Item
let reference_item_two = &reference_item; // This is type &&Item
item.compare_number(8); // the method works
reference_item.compare_number(8); // it works here too
reference_item_two.compare_number(8); // and here
}
因此,请记住:使用时 .
运算符,您不必担心 *
。
Mutable references
如果要使用引用来更改数据,则可以使用可变引用。为了便于参考,您可以编写
fn main() {
let mut my_number = 8; // don't forget to write mut here!
let num_ref = &mut my_number;
}
因此,让我们将其添加到 my_number
中使用num_ref + = 10
,因为 num_ref
不是*
。*
表示我不需要引用,我想要引用后面的值。换句话说,一个 *
会删除一个&。
fn main() {
let mut my_number = 8;
let num_ref = &mut my_number;
*num_ref += 10; // Use * to change the i32 value.
println!("{}", my_number);
}
因为使用 &
被称作 “referencing”*
被称作 “dereferencing”,
Rule 1: 如果您只有不可变的引用,则可以有任意多个。Rule 2: 如果您有可变的引用,则只能有一个。您不能有不可变的引用和可变的引用。
这是因为可变引用可以更改数据。如果在其他引用正在读取时更改数据,则可能会遇到问题。这是带有不可变借位的可变借位的示例:
fn main() {
let mut number = 10;
let number_ref = &number;
let number_change = &mut number;
*number_change += 10;
println!("{}", number_ref); // ⚠️
}
error[E0502]: cannot borrow `number` as mutable because it is also borrowed as immutable
--> src\main.rs:4:25
|
3 | let number_ref = &number;
| ------- immutable borrow occurs here
4 | let number_change = &mut number;
| ^^^^^^^^^^^ mutable borrow occurs here
5 | *number_change += 10;
6 | println!("{}", number_ref);
| ---------- immutable borrow later used here
不过如下的用法是可以的:
fn main() {
let mut number = 10;
let number_change = &mut number; // create a mutable reference
*number_change += 10; // use mutable reference to add 10
let number_ref = &number; // create an immutable reference
println!("{}", number_ref); // print the immutable reference
}
编译器知道我们使用 number_change
来更改数字,但是没有再次使用它,即我们不会同时使用不可变和可变的引用。
函数引用
引用对于函数非常有用。
fn main() {
let country = String::from("Austria");
print_country(country); // We print "Austria"
print_country(country); // ⚠️ That was fun, let's do it again!
}
fn print_country(country_name: String) {
println!("{}", country_name);
}
它不起作用,因为 country
被销毁了。这是如何做:
Step 1: 我们创建String
country
. country
是所有者。 Step 2: 我们给予country
至print_country
. print_country
没有一个 ->
, 因此它不会返回任何内容。后print_country
完成,我们的String
现在已经死了。Step 3: 我们尝试给country
至print_country
,但我们已经做到了。我们没有country
给予。
我们可以通过添加 &
来解决这个问题:
fn main() {
let country = String::from("Austria");
print_country(&country); // We print "Austria"
print_country(&country); // That was fun, let's do it again!
}
fn print_country(country_name: &String) {
println!("{}", country_name);
}
这是使用可变变量的函数示例。
fn main() {
let mut country = String::from("Austria");
add_hungary(&mut country);
}
fn add_hungary(country_name: &mut String) {
country_name.push_str("-Hungary"); // push_str() adds a &str to a String
println!("Now it says: {}", country_name);
}
因此得出结论:
fn function_name(variable: String)
接受一个字符串并拥有它。如果没有返回任何内容,则该变量将在函数完成后死亡。fn function_name(variable: &String)
借用一个字符串,可以看一下。fn function_name(variable: &mut String)
借用字符串并可以更改它。
这是一个看起来像可变引用的示例,但有所不同。
fn main() {
let country = String::from("Austria"); // country is not mutable
adds_hungary(country);
}
fn adds_hungary(mut country: String) { // but adds_hungary takes the string and it is mutable!
country.push_str("-Hungary");
println!("{}", country);
}
这怎么可能?这是因为 mut country
不是引用:
Clone
fn main() {
let country = String::from("Kiribati");
prints_country(country.clone()); // make a clone and give it to the function
prints_country(country);
}
fn prints_country(country_name: String) {
println!("{}", country_name);
}
当然,如果
fn main() {
let mut country = String::from("Kiribati"); // country is mutable
let country_ref = &country; // country_ref needs a reference
changes_country(&mut country); // changes_country needs a &mut ref
println!("{}", country_ref); // ⚠️ immutable and mutable borrow together
}
fn prints_country(country_name: String) {
println!("{}", country_name);
}
fn changes_country(country_name: &mut String) {
country_name.push_str(" is a country");
println!("{}", country_name);
}
也许我们可以更改顺序,但也可以只使用
fn main() {
let mut country = String::from("Kiribati"); // country is mutable
let country_ref = &country; // country_ref needs a reference
changes_country(&mut country.clone()); // give changes_country a clone instead
println!("{}", country_ref); // now the code works
}
fn prints_country(country_name: String) {
println!("{}", country_name);
}
fn changes_country(country_name: &mut String) {
country_name.push_str(" is a country");
println!("{}", country_name);
}