什么是所有权,拥有什么?
资源被哪个变量拥有,资源一般指内存。
1、移动赋值
①会移动=右边的变量
②在c++中,这样的操作是拷贝构造;而在rust中,这样会移动。c++默认情况下给了程序员最大的自由度,而rust正好相反。
let s1 = String::from("hello");
let s2 = s1; // 所有权从s1移动到s2,s1已经是无效的了,不能再使用
对于基本数据类型,整型、浮点型、bool、char等,数据保存到栈上,默认支持Copy语义,赋值操作执行的是拷贝,而不是移动。
let data1 = 10;
let data2 = data1;
println!("data1: {}, data2: {}", data1, data2);
2、调用函数
①值传递,与赋值类似,也是会转移所有权。赋值和值传递,就类似于c++中的unique_ptr,即独占指针,语义是类似的。rust的变量默认都是unique的,并且是const的。
②引用传递,和c++有不一样的地方,c++的函数形参如果接受引用那么就是std::string &str这样的方式,函数调用处的实参不需要使用&来指定,rust中的函数声明以及实参调用的地方都需要使用&来指定是一个引用。否则就会报错。
let s7 = String::from("borrowing");
let len = calculate_length(&s7); // 传递引用,不转移所有权
fn calculate_length(s: &String) -> usize {
s.len()
} // s离开作用域,但因为它没有所有权,所以不会drop任何东西
3、引用赋值
引用在rust中也叫借用。
①不会移动=左边的变量
②默认是不可变引用&;可变应用需要加mut,即&mut
③变量本本身是mut,即可变的,这个变量才可以被可变引用;如果这个变量不是可变的,那么就不能被可变引用。mut变量可以被不可变引用,也可以被可变引用;非mut变量,只能被不可变引用。
④在同一个作用域,只能有一个可变引用,或者1个或多个不可变引用,可变引用和不可变引用不能同时存在。这个约束类似于linux中的读写锁,在同一时刻,写锁可读锁不能同时加锁;统一时刻,只能有一个写锁;统一时刻,可以有多个读锁。
⑤当不可变引用和可变引用同时存在,或者多个可变引用同时存在时,引用的作用域需要根据实际的代码情况进行分割,代码不能存在自相矛盾的地方。
比如下边的代码,打印r3的话,就说明r3的作用域要持续到println这一行,但是在中间又有个可变引用r4,这就是自相矛盾。如果println这一行打印r4,那么便没有自相矛盾,r3的作用域在r4这一行之前就结束了。
let r3 = &mut s9; // 可变引用 - 在不可变引用作用域结束后允许
let r4 = &mut s9;
println!("r3: {}", r3);
let mut s9 = String::from("rules");
let r1 = &s9; // 不可变引用
let r2 = &s9; // 另一个不可变引用 - 允许
println!("r1: {}, r2: {}", r1, r2);
let r3 = &mut s9; // 可变引用 - 在不可变引用作用域结束后允许
println!("r3: {}", r3);
//println!("r3: {}, r2: {}", r3, r2);//同时使用可变引用和不可变引用
4、可以使用clone方法,类似于c++中的拷贝构造
rust
fn main() {
// 示例1: 所有权转移
println!("=== 所有权转移 ===");
let s1 = String::from("hello");
// s1 = String::from(" world");
let s2 = s1; // 所有权从s1移动到s2
//println!("{}", s1); // 这行会编译错误!s1不再有效
println!("s2: {}", s2);
// 示例2: 克隆(深拷贝)
println!("\n=== 克隆 ===");
let s3 = String::from("world");
let s4 = s3.clone(); // 创建数据的完整副本
println!("s3: {}, s4: {}", s3, s4); // 两者都有效
// 示例3: 函数调用中的所有权
println!("\n=== 函数中的所有权 ===");
let s5 = String::from("rust");
takes_ownership(s5); // s5的所有权移动到函数中
//println!("{}", s5); // 错误!s5不再有效
let s6 = gives_ownership(); // 从函数获取所有权
println!("从函数获取的: {}", s6);
// 示例4: 引用(借用)
println!("\n=== 引用(借用)===");
let s7 = String::from("borrowing");
let len = calculate_length(&s7); // 传递引用,不转移所有权
println!("'{}' 的长度是: {}", s7, len); // s7仍然有效
// 示例5: 可变引用
println!("\n=== 可变引用 ===");
let mut s8 = String::from("hello");
change_string(&s8);
println!("修改后: {}", s8);
// 示例6: 引用规则验证
println!("\n=== 引用规则 ===");
let mut s9 = String::from("rules");
let r1 = &s9; // 不可变引用
let r2 = &s9; // 另一个不可变引用 - 允许
println!("r1: {}, r2: {}", r1, r2);
let r3 = &mut s9; // 可变引用 - 在不可变引用作用域结束后允许
println!("r3: {}", r3);
//println!("r3: {}, r2: {}", r3, r2);//同时使用可变引用和不可变引用
}
fn takes_ownership(some_string: String) {
println!("在函数中: {}", some_string);
} // some_string离开作用域,drop被调用
fn gives_ownership() -> String {
let some_string = String::from("ownership");
some_string // 所有权转移给调用者
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s离开作用域,但因为它没有所有权,所以不会drop任何东西
fn change_string(s: &String) {
//s.push_str(", world!");
}
rust函数声明的格式:
fn 函数名(形参名:形参类型)->返回值类型{}
rust函数返回,只需要把要返回的结果放在最后一行,然后这行没有以;结尾,这就表示返回。如果函数不是在最后一行返回,那么需要使用return关键字。最后一行,使用return也是可以的。
切片:
如下代码,s2就是切片,切片天生就是引用。切片是针对String或者数据的其中一段的引用。
rust
fn main() {
let mut s1 = String::from("hello world");
let s2 = &s1[0..5];
println!("s1 {}, s2 {}",s1,s2);
s1.clear();
}
字符串切片的类型用 &str来表示。
rust
fn main() {
let mut s = String::from("hello world");
let word = first_word(&s);
println!("first word {}", word);
}
fn first_word(s: &str) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}