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

幻灰龙 幻灰龙 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区

上一条: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!
}


 

...全文

相关推荐

rust中文教程

rust中文教程

ericpenhu

深入理解 Rust 生命周期(可能是全网最透彻的解读了)

本文通过生动的代码示例和清晰的逻辑分析,深入浅出地讲解了Rust生命周期的核心概念。作者首先以一个悬垂引用的例子引出生命周期标注的必要性,然后系统性地阐述了四条关键规则:引用生命周期不能超过被引用值、生命周期是编译期概念、引用传播生命周期依赖而值会截断依赖、多输入引用时输出引用的生命周期是输入引用的交集。文章特别强调要区分编译期静态分析和运行时动态执行的思维差异,并指出生命周期标注的本质是帮助编译器进行借用检查。通过将抽象概念具象化为伪代码标注,作者为读者提供了理解Rust生命周期的有效"抓手",使这个原本

Laurence 

一文掌握Rust编程中的生命周期.pdf

内容概要:这篇文章深入介绍了在Rust编程中的生命周期概念,强调了在Rust语言中每个引用都有其生命周期,即引用在程序执行过程中具有自身的作用域,一旦超出作用域范围,其生命周期也随之结束,值变得无效。文章通过解释生命周期的概念和重要性,帮助读者更好地理解和应用Rust编程中的引用和生命周期管理。 适用人群:适合对Rust编程语言有一定了解的开发者、学习者以及对系统级编程和内存管理感兴趣的人群。无论是初学者还是有一定Rust编程经验的用户,都可以从本文中深入了解Rust中的生命周期概念及其应用。 使用场景及目标:可用于系统级编程、并发编程、内存安全等场景。通过学习Rust编程中的生命周期概念,读者可以提高对内存管理和引用生命周期的理解,编写更安全、高效的Rust程序,避免内存泄漏和悬空引用等问题。 其他说明:建议读者在阅读文章的同时结合实际代码示例进行练习和实践,加深对Rust生命周期的理解和掌握。生命周期管理是Rust语言的重要特性之一,对于编写高质量、安全的代码至关重要。通过掌握Rust中生命周期的概念和应用,读者可以提升编程技能,编写更可靠的Rust程序。祝愿读者通过本文学习

27-1994

lifetime-variance-example:工作Rust示例演示差异

Rust的生命周期方差 这个工作示例涵盖了Rust的变异基础,因为它适用于生命周期,以素养的编程风格编写。 这是一个工作的Rust板条箱。 克隆此仓库并运行cargo build以与其一起玩。 转到开始! 执照

Friedrich ZHAO

Rust的生命周期练习和讲解

本资源主要讲解了Rust的生命周期标注,以及添加生命周期的方法 并介绍&' static生命周期的使用方法 并介绍Rust的生命周期如何在Trait Bound上使用

CakeAL
评论 2
收藏 已收藏
分享
返回顶部
幻灰龙
10x Rust 1,726 成员 130 内容