Rust (三)Owner语义与生命周期

一、所有权转移

一般情形下的函数调用移动所有权。

// takes_ownership 取得调用函数传入参数的所有权,所以变量进来了就出不去了
fn takes_ownership(some_string: String) {
    println!("{}", some_string);
} // 这里,some_string 移出作用域并调用 `drop` 方法。占用的内存被释放

// gives_ownership 将返回值移动给调用它的函数
fn gives_ownership() -> String {
    let some_string = String::from("hello");
    some_string // 返回 some_string 并移出给调用的函数
}

// takes_and_gives_back 将传入字符串并返回该值
fn takes_and_gives_back(mut a_string: String) -> String {
    a_string.push_str(", world");
    a_string  // 返回 a_string 将所有权移出给调用的函数
}

fn main()
{
    let s1 = gives_ownership();
    takes_ownership(s1);    // 所有权转给了 takes_ownership 函数
    // println!("s1= {}", s1);   // s1 不可用了
    
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2);  // s2 被移动到 takes_and_gives_back 中
    
    //println!("s2={}", s2);   //s2 不可用了
    println!("s3={}", s3);
}

二、Owner + Move 的语义也会带来一些复杂度。

#[derive(Debug)]          // 使用 `{:?}`的方式输出结构体
struct Person {
    name :String,
    email:String,
}

let _name = p.name;                // 把结构体 Person::name Move掉
println!("{} {}", _name, p.email); //其它成员可以正常访问
// println!("{:?}", p);            //编译出错 "value borrowed here after partial move"
p.name = "Hao Chen".to_string();   // Person::name又有了。
println!("{:?}", p);               //可以正常的编译了

三、生命周期

Rust为了解决“野引用”的问题,在有多个变量引用到一个对象上,还不能使用额外的引用计数来增加程序运行的复杂度。那么,Rust就要管理程序中引用的生命周期了,而且还是要在编译期管理,如果发现有引用的生命周期有问题的,就要报错。

fn order_string(s1 : &str, s2 : &str) -> (&str, &str) {
    if s1.len() < s2.len() {
        return (s1, s2);
    }
    return (s2, s1);
}

let str1 = String::from("long long long long string");
let str2 = "short string";

let (long_str, short_str) = order_string(str1.as_str(), str2);

println!(" long={} nshort={} ", long_str, short_str);

我们有两个字符串,str1 和 str2 我们想通过函数 order_string() 对其排序,你会发现,这段代码编译不过。编译器会告诉你,order_string() 返回的 引用类型 &str 需要一个 lifetime的参数 – “ expected lifetime parameter”。这是因为Rust编译无法通过观察静态代码分析返回的两个引用返回值,到底是(s1, s2) 还是 (s2, s1) ,因为这是运行时决定的。所以,返回值的两个参数的引用没法确定其生命周期到底是跟 s1 还是跟 s2,这个时候,编译器就不知道了。

生命周期标注
fn long_string<'a>(s1 : &'a str, s2 : &'a str) -> (&'a str, &'a str) {
    if s1.len() > s2.len() {
        return (s1, s2);
    }
    return (s2, s1);
}
单引用—无需标注生命周期

函数 foo() 的参数和返回值都是一个引用,他们的生命周期是一样的,编程器可以自己推导出来,也就可以编译通过。

fn foo (s: &mut String) -> &String {
    s.push_str("coolshell");
    s
}

let mut s = "hello, ".to_string();
println!("{}", foo(&mut s))
包含引用类型成员的结构体
#[derive(Debug)]

struct User<'a>{
    username: &'a str,
    email:String,
    age:u8,
}

fn main() {
    let word = String::from("zhang_san");
    let email_ = String::from("zhang_san@qq.com");

    let stu = User{username:&word,email:email_,age:12};
    println!("{:?}",stu);
}

构造函数,我都不知道该如何构造了,在P235 中建造者模式中并没有引用,本来想参考来着

#[derive(Debug)]

struct User<'a>{
    username: &'a str,
    email:String,
    age:u8,
    score:&'a i8,
}


impl <'a> User<'a> {
    // fn new() ->User<'a>{
    //     //
    // }

    fn set_username(&mut self, s : &'a str) {
        self.username = s;
    }
    fn set_score(&mut self,  i : &'a i8) {
        self.score = i;
    }
}


fn main() {
    let word0 = String::from("zhang_san");
    let word1 = String::from("li_si");
    let email_ = String::from("zhang_san@qq.com");
    let score_0 = 90;
    let score_1 = 90;

    let mut stu = User{username:&word0,email:email_,age:12,score:&score_0};
    println!("{:?}",&stu); //User { username: "zhang_san", email: "zhang_san@qq.com", age: 12, score: 90 }

    let stu2 = &stu.set_username(&word1);
    println!("{:?}",stu2);   // ()

    let stu3 = &stu.set_score(&score_1);
    println!("{:?}",stu3);   // ()
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongpingWang

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值