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章- 示例```rustfn 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);
