我正在学习Rust中的Traits和Trait Object。在Trait chapter中,我解决了第6个练习,与编译器建议的不同。下面的代码定义了两个结构体(Sheep
和Cow
)和一个trait(Animal
)。Sheep
和Cow
都通过提供自己的noise
方法实现来实现Animal
trait。
有两个函数,random_animal_if
和random_animal_match
,它们接受一个参数并返回一个对动态trait对象的引用。
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
对象。其中之一是对浮点数输入使用条件。另一种是在给定的字符串切片上使用模式匹配。逻辑是相同的,但是如果我在random_animal_if
返回类型中省略了&'static
生存期规范,那么编译器就会抛出这个错误:
错误[E0106]:缺失寿命说明符
有趣的是,如果输入参数类型从f64
更改为&str
,则可以删除静态生命周期注解。为什么?这两种类型有什么区别?
2条答案
按热度按时间ej83mcc01#
这是因为Rust的lifetime elision rules。
如果你有一个函数,它接受一个引用作为参数并返回一个引用,那么编译器会推断输出从输入中借用,看起来像这样:
事实上,函数返回非静态引用的唯一方法是从参数中借用返回的数据。
但是,在您的代码中,
random_animal_match
的主体不会从参数中借用返回值。编译器仍然推断出省略的生存期 *,就好像 * 是这种情况,但实际上返回类型中的生存期总是'static
。这意味着函数返回类型中的生存期受到过度限制。如果函数的调用者在输入&str
被删除后试图使用返回的&dyn Animal
,则会得到编译器错误,尽管这实际上不应该是一个问题:为了最大限度地提高这个函数的灵活性,你应该将生存期设置为返回类型
'static
:juzqafwq2#
&str
是一个引用,有一个与之关联的生存期,而f64
没有。f64
类型由以下函数拥有:它被存储在堆栈上,并将在函数返回时被释放。基础字符串由其他函数拥有,只是被借用。返回的值也是一个引用。这意味着它必须有一个生命。在某些情况下,不需要指定生存期,因为可以推断出它。有一个基本规则:
如果参数中仅使用了一个生存期(省略与否),则该生存期将分配给所有省略的输出生存期。
在
f64
的例子中,没有lifetime参数,因为它不是一个引用。因此,该规则不适用。在&str
的例子中,有一个生命周期参数被忽略了。因此,在参数中使用了一个生命周期,因此规则适用,返回类型获得相同的生命周期。在f64
的情况下,该规则不适用,因此没有将生存期分配给返回类型,但这意味着函数签名无效,因为缺少生存期说明符。现在,这意味着您可以在
&str
的情况下省略lifetime参数,但它确实改变了语义。推断的生存期将与字符串的生存期相同,这意味着每当字符串被释放时,返回的对动物的引用也将无效。这可能是不方便的,如果目的是保持动物周围的时间比字符串。因此,在这两种情况下,最好将生存期指定为'static
。