了解 Rust 的 Trait 对象和不同函数签名中的生命周期注释

问题描述 投票:0回答:1

我正在研究 Rust 中的 Traits 和 Trait 对象。在Trait章节中,我以与编译器建议不同的方式解决了第六个练习。以下代码定义了两个结构体(

Sheep
Cow
)和一个特征(
Animal
)。
Sheep
Cow
都通过提供自己的
Animal
方法实现来实现
noise
特征。

有两个函数,

random_animal_if
random_animal_match
,它们接受参数并返回对动态特征对象的引用。

struct Sheep {}
struct Cow {}

trait Animal {
    fn noise(&self) -> String;
}

impl Animal for Sheep {
    fn noise(&self) -> String {
        "baaaaah!".to_string()
    }
}

impl Animal for Cow {
    fn noise(&self) -> String {
        "moooooo!".to_string()
    }
}

fn random_animal_if(random_number: f64) -> &'static dyn Animal {
    if random_number < 10.0 {
        &Sheep {}
    } else if random_number > 20.0 {
        &Cow {}
    } else {
        panic!()
    }
}

fn random_animal_match(random_string: &str) -> &dyn Animal {
    match random_string {
        "sheep" => &Sheep {},
        "cow" => &Cow {},
        _ => panic!(),
    }
}

fn main() {
    let animal = random_animal_if(21.0);
    println!("Randomly animal says {}", animal.noise());
    let animal = random_animal_match("sheep");
    println!("Randomly animal says {}", animal.noise());
}

这两个函数都会根据输入创建并返回

Sheep
Cow
对象。其中之一在浮点数输入上使用条件。另一个在给定的字符串切片上使用模式匹配。逻辑是相同的,但如果我在
&'static
返回类型中省略
random_animal_if
生命周期规范,那么编译器会抛出此错误:

错误[E0106]:缺少生命周期说明符

有趣的是,如果输入参数类型从

f64
更改为
&str
,则可以删除静态生命周期注释。为什么?这两种类型有什么区别?

rust lifetime trait-objects
1个回答
0
投票

&str
是一个引用,并具有与其关联的生命周期,而
f64
则没有。
f64
类型属于该函数:它存储在堆栈中,并在函数返回时被释放。底层字符串由其他某个函数拥有,并且只是借用的。

返回值也是一个参考。这意味着它必须有寿命。在某些情况下,不需要指定生命周期,因为可以推断它。为此有一个基本的规则

如果参数中仅使用了一个生命周期(是否已省略),则该生命周期将分配给所有已省略的输出生命周期。

f64
情况下,没有生命周期参数,因为它不是引用。因此,该规则不适用。在
&str
情况下,有一个生命周期参数已被省略(省略)。因此,参数中仅使用一个生命周期,因此规则适用并且返回类型具有相同的生命周期。在
f64
的情况下,该规则不适用,因此没有为返回类型分配生命周期,但这意味着函数签名无效,因为缺少生命周期说明符。

现在,这意味着您可以在

&str
的情况下省略生命周期参数,但它确实改变了语义。推断的生命周期将与字符串的生命周期相同,这意味着每当字符串被释放时,返回的对动物的引用也会变得无效。如果目的是让动物保持比绳子更长的时间,这可能会很不方便。因此,在这两种情况下,最好将生命周期指定为
'static

© www.soinside.com 2019 - 2024. All rights reserved.