我正在研究 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
,则可以删除静态生命周期注释。为什么?这两种类型有什么区别?
&str
是一个引用,并具有与其关联的生命周期,而 f64
则没有。 f64
类型属于该函数:它存储在堆栈中,并在函数返回时被释放。底层字符串由其他某个函数拥有,并且只是借用的。
返回值也是一个参考。这意味着它必须有寿命。在某些情况下,不需要指定生命周期,因为可以推断它。为此有一个基本的规则:
如果参数中仅使用了一个生命周期(是否已省略),则该生命周期将分配给所有已省略的输出生命周期。
在
f64
情况下,没有生命周期参数,因为它不是引用。因此,该规则不适用。在 &str
情况下,有一个生命周期参数已被省略(省略)。因此,参数中仅使用一个生命周期,因此规则适用并且返回类型具有相同的生命周期。在 f64
的情况下,该规则不适用,因此没有为返回类型分配生命周期,但这意味着函数签名无效,因为缺少生命周期说明符。
现在,这意味着您可以在
&str
的情况下省略生命周期参数,但它确实改变了语义。推断的生命周期将与字符串的生命周期相同,这意味着每当字符串被释放时,返回的对动物的引用也会变得无效。如果目的是让动物保持比绳子更长的时间,这可能会很不方便。因此,在这两种情况下,最好将生命周期指定为 'static
。