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[..]
}
相关推荐
云帆小二2 小时前
从开发语言出发如何选择学习考试系统
开发语言·学习
光泽雨3 小时前
python学习基础
开发语言·数据库·python
q***49863 小时前
数据库操作与数据管理——Rust 与 SQLite 的集成
数据库·rust·sqlite
百***06013 小时前
python爬虫——爬取全年天气数据并做可视化分析
开发语言·爬虫·python
jghhh013 小时前
基于幅度的和差测角程序
开发语言·matlab
fruge4 小时前
自制浏览器插件:实现网页内容高亮、自动整理收藏夹功能
开发语言·前端·javascript
曹牧4 小时前
Java中处理URL转义并下载PDF文件
java·开发语言·pdf
未来之窗软件服务4 小时前
幽冥大陆(二十二)dark语言智慧农业电子秤读取——东方仙盟炼气期
开发语言·windows·golang·东方仙盟·东方仙盟sdk
逐步前行4 小时前
C项目--羊了个羊(两关全)--含源码
c语言·开发语言
IMPYLH5 小时前
Lua 的 assert 函数
开发语言·笔记·junit·单元测试·lua