9. Rust 函数参数上的生命周期(lifetime)标记

幻灰龙 2021-07-24 08:39:29

上一条:C++ 生命周期回顾 下一条:结构体成员的生命周期(lifetime)标记


(1)首先,Rust的编译器需要明确地知道一个借用对象是否还是有效的。例如返回一个新创建的对象肯定是有效的,不需要检查。
 

fn create_obj():Object{
  Object{}
}


 

 

(2)但是,显然你不能返回一个局部对象的借用,因为局部对象在函数结束后超出作用域就被释放了:
 

fn get_obj():&Object{ // compile error
  const obj = Object{};
  &obj
}


 

 

(3)不过,如果这个借用本来就是从外部传入的,那当然可以返回,函数结束后这个对象还是有效的:
 

// I am borrowed from caller
// return borrow to the caller is safe
fn process_obj(obj:&Object):&Object{
  &obj
}


 

 

(4)然而,如果你传入了两个对象的借用,内部做了条件返回。那么编译器没那么智能,它并不总是能推断出返回的是哪个对象的借用:
 

// compile error!
// where am I come from?
fn process_objs(x:&Obejct, y:&Object):&Object{ 
  if(x.is_ok()){
    &x
  }else{
    &y
  }
}


 


(5)因此,Rust保留了内部的一种编译器内部的,本来是隐式添加记号,也就是生命周期(lifetime),通过显式添加生命周期标记,解决上述问题:
 

// I am come from 'a lifetime, NOT 'b
fn process_objs<'a,'b>(x: &'a Obejct, y:&'b Object):&'a Object{ 
  &x
}

// I am come from 'a lifetime, x,y,and result are all 'a lifetime
fn process_objs<'a>(x: &'a Obejct, y:&'a Object):&'a Object{ 
  if(x.is_ok()){
    &x
  }else{
    &y
  }
}


 

 

(6)事实上,当你没写lifetime标记时,每个对象也都是有对应的lifetime的,例如编译器为每个对象生成一个不同的lifetime
 

fn test<'a,'b>(x: &'a Obejct, y:&'b Object){ 
  
}


 

 

(7)因为默认生成的都是不同的,所以返回值如果不标记是谁,编译器就无法推断:

 

fn test<'a,'b,'c>(x: &'a Obejct, y:&'b Object):&'c Object{ // 'c is 'a or 'b ? 
  if(x.is_ok()){
    &x
  }else{
    &y
  }
}


(8)所以如果我们显式标记,并让两个变量用同一个,就能解决,这就是告诉编译器,`'c='a='b`:
 

fn test<'a>(x: &'a Obejct, y:&'a Object):&'a Object{ // 'c='a='b, they are all 'a 
  if(x.is_ok()){
    &x
  }else{
    &y
  }
}


 


(9)看到这里,你也应该知道了lifetime标记的名字是任意的,只是一个【形参】,代表的是这个借用对象的生命周期作用域的名字:
 

{
    let obj;                  //---'a start here
    {                   
        let x = Obj{};        //---'b start here
        
        obj = &x;             //---'b finish here
    }                   
    
    println!("obj: {}", obj); //---'a finish here, 'b is out of scope, compile error!
}

// #[derive(Apparition)]
{
    // 当然你可以用任意合法的符号替换'a和'b,它们只是个名字
    let obj<'b>;                  //---'a start here
    {                   
        let x = Obj{};             //---'b start here
        
        obj<'b> = &'b x;           //---'b finish here
    }                   
    
    // obj借用是否有效,仅仅取决于它实际上它所借用的对象的生命周期作用域'b范围是否大于等于'a
    // 一个'b作用域内的对象的借用,在'a内被调用,但是'b比'a小,调用的时候'b已经不存在了
    // 因此编译器宣布:这是非法的。
    println!("obj: {}", obj<'b>); //---'a finish here, 'b is out of scope, compile error!
}


 

...全文
2137 2 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiaoyuezhao 2021-08-13
  • 打赏
  • 举报
回复

不错

幻灰龙 2021-08-13
  • 举报
回复
@xiaoyuezhao 有什么建议不

1,725

社区成员

发帖
与我相关
我的任务
社区描述
Rust是新一代大规模底层系统平台开发的强力选项,拥有现代的类型系统,精确的生命周期控制,流畅的表达力和错误处理,以及明晰的异步编程范式。
rust 个人社区
社区管理员
  • 幻灰龙
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
社区主要目的: 1. 讨论Rust的核心语法语义 2. 讨论Rust的编程范式、最佳实践。 3. 讨论10x创新技术

试试用AI创作助手写篇文章吧