1 所有权
1.1 所有权
对变量进行赋值、作为参数传入函数、作为返回值从函数返回时,根据变量类型是否实现了Copy
特性,有不同的行为
- 类型实现了
Copy
特性:资源被复制,原变量仍然有效 -
1.3
Copy
特性 所有基础类型(整数、浮点数、字符、布尔量)都实现了
Copy
特性- 共享引用类型实现了
Copy
特性;独占引用类型没有实现Copy
特性
无论是编译器自动为基础类型实现Copy
特性,还是通过明确声明为自定义类型实现Copy
特性,Copy
行为都是按比特复制,这个行为不可更改
- 全部字段都实现了
Copy
特性时,自定义类型可以实现Copy
特性- 注意:是可以实现
Copy
特性,不是实现了Copy
特性 - 在可以实现
Copy
特性的前提下,可以用两种方法之一实现Copy
特性- 使用
#[derive(Copy)]
- 使用
impl Copy for 类型名{}
:不需要提供任何方法
- 使用
- 注意:是可以实现
Clone
是Copy
的基类型,实现Copy
的类型,必须也实现Clone
对
Copy
特性的使用,总是自动的,无法明确要求使用Copy
特性1.4
Clone
特性所有基础类型(整数、浮点数、字符、布尔量)都实现了
Clone
特性- 编译器自动为基础类型实现的
Clone
行为是按比特复制,这个行为不可改变 - 可以为任何自定义类型用两种方式之一实现
Clone
- 使用
#[derive(Clone)]
:要求自定义类型的字段都是实现了Clone
的类型 - 使用
impl Clone for 类型名{}
:需要提供clone
方法:fn clone(&self) -> Self
,其行为可以自行定义
- 使用
对
Clone
行为的调用,总是手动的,编译器不会自动调用Clone
特性1.5 Copy
和Clone
的对比相同点
- 编译器为所有基础类型自动实现了
Copy
和Clone
特性 - 编译器为所有基础类型实现的
Copy
/Clone
行为都是按比特复制,这个行为不可改变 - 编译器不会自动为自定义类型实现
Copy
/Clone
特性,必须用两种方法之一明确声明 - 所有字段都实现了
Copy
/Clone
特性时,可以通过#[derive]
为自定义类型实现Copy
/Clone
特性 - 通过
#[derive]
实现Copy
/Clone
特性时,特性行为都是按比特复制,不需要额外提供方法代码
- 编译器为所有基础类型自动实现了
- 差异点
- 只有所有字段都实现了
Copy
的时候,自定义类型才能够实现Copy
,且Copy
行为是按比特复制,这个行为不可改变 - 无论是否所有字段都实现了
Clone
,都可以为自定义类型实现Clone
,且通过impl Clone for 类型
实现Clone
时,可自定义特性行为 - 对
Copy
特性的调用,总是自动的:赋值、作为参数传入函数、作为返回值从函数传出时,- 如果类型实现了
Copy
特性,则自动使用Copy
特性 - 如果类型没有实现
Copy
特性,则转移所有权
- 如果类型实现了
- 对
Clone
特性的调用,总是手动的:必须明确地调用clone
方法来实现对Clone
特性的调用 Clone
是Copy
的基础特性,实现Copy
特性时,必须同时实现Clone
特性;反之则不成立:实现Clone
特性时,不一定需要实现Copy
特性- 示例```rust
[derive(Debug,Copy)]
struct Foo { a: i32, b: bool, }
- 只有所有字段都实现了
impl Clone for Foo{ // 为自定义类型实现Clone时,可自定义Clone行为 fn clone(&self) -> Self{ Foo{ a: self.a + 10, b: !self.b, } } }
fn main() { let x = Foo{ a: 1, b: true, }; // 因为实现了Copy特性,所以赋值时自动调用Copy特性,而不是转移所有权 let mut y = x; y.a = 123; let d = y.clone(); println!(“{:?}”,x);// Foo { a: 1, b: true } println!(“{:?}”,y);// Foo { a: 123, b: true } println!(“{:?}”,d);// Foo { a: 133, b: false } }
<a name="218c4c6f"></a>
# 2 引用与借用
- 通用引用可以使用值,但不获取所有权
- 因为没有所有权,所以引用离开作用域不会导致值被释放
- 通过引用使用值称作借用
- 引用默认是不可变的,用`mut`修饰使之成为可变引用,即可通过引用修改值
- 任何时刻,一个值只能有多个不可变引用;或者一个可变引用。可变引用与不可变引用是互斥的。
- 编译器会阻止野指针(dangling pointer)
- 返回引用类型时通常需要生命周期注解,详见第10章
- 示例```rust
fn main() {
let reference_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello");
&s
}
// 值离开作用域后被释放,但是返回的引用不会释放,这会导致引用使用已经释放的值,产生dangling pointer
// Rust编译器会阻止这种情况发生,这段代码通不过编译。如果不返回引用,直接返回值,则返回时所有权被转移,不会产生野指针,编译通过。
3 切片
- 切片是另一种没有所有权的类型,表示引用数组或者字符串的一部分
- 切片语法为
&数组/字符串变量[start..end]
,切片包括start
指示的元素,不包括end
指示的元素 - 对
String
类型使用切片的时候,索引值表示字节偏移量,而不是字符偏移 - 要特别注意对中文的处理:每个中文字符占3个字节。如果运行中字节偏移量不在字符边界上,则会
panic
- 示例```rust
fn main() {
let s = String::from(“中文Chinese”);
println!(“{}”,&s[..3]);// 输出”中”
for c in s.chars(){
} } ```println!("{}",c);