rust:所有权

什么是所有权,拥有什么?

资源被哪个变量拥有,资源一般指内存。

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[..]
}
相关推荐
天天进步20152 分钟前
Linux 实战:如何像查看文件一样“实时监控” System V 共享内存?
开发语言·c++·算法
凛_Lin~~4 分钟前
安卓/Java语言基础八股文
java·开发语言·安卓
八年。。7 分钟前
Python 版本确认方法
开发语言·笔记·python
foundbug9999 分钟前
基于MATLAB Simulink的双向DC-DC变换器仿真程序实现
开发语言·matlab
李广坤16 分钟前
Rust基本使用
后端·rust
元亓亓亓19 分钟前
考研408--操作系统--day8--操作系统--虚拟内存&请求分页&页面置换/分配
android·java·开发语言·虚拟内存
裤裤兔37 分钟前
Python打印输出换行
开发语言·python
一水鉴天38 分钟前
整体设计 定稿 之24+ dashboard.html 增加三层次动态记录体系仪表盘 之2 程序 (Q208 之2)
开发语言·前端·javascript
啦哈拉哈39 分钟前
【Python】知识点零碎学习3
开发语言·python·学习
mengzhi啊44 分钟前
Qt自绘制动态字体,模糊的,毛茸茸的fuzzy。
开发语言·qt