目录生命周期深入生命周期&'static和T:'static函数式编程:闭包、迭代器闭包Closure迭代器Iterator生命周期深入生命周期什么是生命周期?生命周期是Rust中用来保证引用有效性的工具。它确保了在任何时刻,所有引用都指向有效的内存。为
为什么需要生命周期?
声明与使用
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
'a
是一个生命周期参数,它被绑定到函数的输入参数 x
和 y
的生命周期上。所有权和借用规则
fn example() {
let s = String::from("hello");
let r1 = &s; // r1 的生命周期被 s 的生命周期所限制
let r2 = &s; // r2 同样受限于 s 的生命周期
println!("r1: {}, r2: {}", r1, r2);
}
// 编译器会确保 r1 和 r2 在 s 有效期内有效
多个生命周期参数 当函数或结构体有多个引用时,需要明确指定不同的生命周期参数。
fn longest_with_another<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// 使用示例
fn main() {
let string1 = String::from("long string is long");
let string2 = String::from("xyz");
let result = longest_with_another(&string1[..], &string2);
println!("The longest string is {}", result);
}
编译器自动推断
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() { x } else { y }
}
// 编译器可以自动推断生命周期
fn main() {
let string1 = String::from("long string is long");
let string2 = String::from("xyz");
let result = longest(&string1[..], &string2);
println!("The longest string is {}", result);
}
特殊之处
'static
是一个特殊的生命周期,表示“全局有效”。'static
生命周期。let s = "hello"; // 字面量字符串,生命周期为 'static
let static_str: &'static str = "hello";
解释
'static
生命周期时,意味着 T 必须能够存在于整个程序运行期间。实际应用
// 定义一个函数,接受一个实现了 'static 生命周期的类型 T 的引用
fn print_lifetime<T: 'static>(t: &T) {
println!("{:?}", t);
}
// 使用示例
print_lifetime(&"hello"); // OK
print_lifetime(&5); // OK
print_lifetime(&vec![1, 2, 3]); // 编译错误,因为 Vec 不实现 'static
全局变量
'static
生命周期。'static
生命周期。static HELLO: &str = "hello";
fn main() {
println!("{}", HELLO);
}
动态分配内存
'static
生命周期。'static
生命周期。fn create_box() -> Box<dyn Any + 'static> {
Box::new(42)
}
fn main() {
let box_value = create_box();
println!("{:?}", box_value);
}
字符串字面量
'static
生命周期。'static
生命周期的函数。fn print_static_str(s: &'static str) {
println!("{}", s);
}
fn main() {
let s = "hello";
print_static_str(s);
}
类型约束 T: 'static
trait MyTrait {}
impl MyTrait for i32 {}
impl MyTrait for String {}
fn process_data<T: MyTrait + 'static>(data: T) {
println!("{:?}", data);
}
fn main() {
process_data(42); // OK
process_data(String::from("hello")); // 编译错误,String 不实现 'static
}
动态调度
Box<dyn Trait>
时,需要确保类型具有 'static
生命周期。trait MyTrait {
fn say_hello(&self);
}
impl MyTrait for i32 {
fn say_hello(&self) {
println!("Hello from an integer!");
}
}
impl MyTrait for String {
fn say_hello(&self) {
println!("Hello from a string!");
}
}
fn process_data(data: Box<dyn MyTrait + 'static>) {
data.say_hello();
}
fn main() {
let boxed_int = Box::new(42);
let boxed_str = Box::new(String::from("hello"));
process_data(boxed_int);
process_data(boxed_str);
}
假设我们要创建一个缓存系统,其中键为字符串,值为任意类型的数据。为了确保安全性,我们希望缓存中的值在整个程序运行期间都是有效的。
use std::collections::HashMap;
struct Cache {
data: HashMap<String, Box<dyn Any + 'static>>, // 使用 trait object 来存储任意类型
}
impl Cache {
fn new() -> Self {
Cache {
data: HashMap::new(),
}
}
fn insert<T: 'static>(&mut self, key: String, value: T) {
self.data.insert(key, Box::new(value));
}
fn get<T: 'static>(&self, key: &str) -> Option<&T> {
self.data.get(key)?.downcast_ref::<T>()
}
}
// 使用示例
fn main() {
let mut cache = Cache::new();
cache.insert("message".to_string(), "Hello, world!".to_string());
cache.insert("number", 123);
if let Some(msg) = cache.get::<String>("message") {
println!("Message: {}", msg);
}
if let Some(num) = cache.get::<i32>("number") {
println!("Number: {}", num);
}
}
这个例子展示了如何利用 T: 'static
确保缓存中的数据在任何时候都是有效的,并且可以被安全地访问。
什么是闭包?
闭包的语法
闭包的分类
// 不可变闭包
let add_one = |x: i32| x + 1;
assert_eq!(add_one(5), 6);
// 可变闭包
let mut count = 0;
let add_to_count = || count += 1;
add_to_count();
assert_eq!(count, 1);
// 借用闭包
let number = 5;
let print_number = |n: &i32| println!("The number is: {}", n);
print_number(&number);
闭包的生命周期注解
fn main() {
let string = String::from("hello");
// 不可变引用
let reference = &string;
let closure = move || println!("Inside the closure: {}", reference);
closure();
// 可变引用
let mut mutable_reference = String::from("world");
let mutable_closure = move || {
mutable_reference.push_str("!");
println!("Inside the closure: {}", mutable_reference);
};
mutable_closure();
}
fn apply<F>(func: F, arg: i32) -> i32
where
F: Fn(i32) -> i32,
{
func(arg)
}
fn main() {
let result = apply(|x| x * x, 5);
assert_eq!(result, 25);
}
什么是迭代器?
迭代器的基本方法
next()
:获取下一个元素。fold()
:折叠操作。map()
:映射操作。filter()
:过滤操作。collect()
:收集结果。let numbers = vec![1, 2, 3, 4, 5];
// 使用 next()
let mut iter = numbers.iter();
assert_eq!(iter.next(), Some(&1));
assert_eq!(iter.next(), Some(&2));
// 使用 fold()
let sum = numbers.iter().fold(0, |acc, &x| acc + x);
assert_eq!(sum, 15);
// 使用 map()
let squares: Vec<_> = numbers.iter().map(|&x| x * x).collect();
assert_eq!(squares, vec![1, 4, 9, 16, 25]);
// 使用 filter()
let evens: Vec<_> = numbers.iter().filter(|&&x| x % 2 == 0).collect();
assert_eq!(evens, vec![2, 4]);
迭代器适配器
filter()
, map()
, enumerate()
, zip()
等。let numbers = vec![1, 2, 3, 4, 5];
// 使用 enumerate()
for (index, &value) in numbers.iter().enumerate() {
println!("Index: {}, Value: {}", index, value);
}
// 使用 zip()
let letters = vec!['a', 'b', 'c', 'd', 'e'];
for (&num, &letter) in numbers.iter().zip(letters.iter()) {
println!("Number: {}, Letter: {}", num, letter);
}
迭代器组合
let numbers = vec![1, 2, 3, 4, 5];
// 先过滤偶数,再平方
let even_squares: Vec<_> = numbers.iter()
.filter(|&&x| x % 2 == 0)
.map(|&x| x * x)
.collect();
assert_eq!(even_squares, vec![4, 16]);
let numbers = vec![1, 2, 3, 4, 5];
// 使用闭包作为 filter 参数
let filtered_numbers: Vec<_> = numbers.iter()
.filter(|&x| *x % 2 == 0)
.collect();
assert_eq!(filtered_numbers, vec![2, 4]);
// 使用闭包作为 map 参数
let squared_numbers: Vec<_> = numbers.iter()
.map(|&x| x * x)
.collect();
assert_eq!(squared_numbers, vec![1, 4, 9, 16, 25]);
let numbers = vec![1, 2, 3, 4, 5];
// 使用闭包进行复杂计算
let result: Vec<_> = numbers.iter()
.filter(|&x| *x % 2 == 0)
.map(|&x| x * x)
.fold(0, |acc, x| acc + x)
.collect();
assert_eq!(result, 20);
实际应用案例
use std::fs::File;
use std::io::{BufRead, BufReader};
fn process_file(file_path: &str) {
let file = File::open(file_path).expect("Failed to open file");
let reader = BufReader::new(file);
let lines: Vec<String> = reader.lines()
.filter_map(Result::ok)
.map(|line| line.trim().to_string())
.collect();
println!("Processed lines: {:?}", lines);
}
fn main() {
process_file("example.txt");
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!