面试题答案
一键面试// 定义一个trait
trait MyTrait {
fn get_data(&self) -> i32;
}
// 定义一个新的结构体
struct NewStruct {
data: i32,
}
// 定义泛型函数
fn combine_data<T1: 'a + MyTrait, T2: 'b + MyTrait, 'a, 'b>(arg1: &'a T1, arg2: &'b T2) -> NewStruct {
let data1 = arg1.get_data();
let data2 = arg2.get_data();
NewStruct { data: data1 + data2 }
}
// 实现MyTrait的结构体示例1
struct Example1 {
value: i32,
}
impl MyTrait for Example1 {
fn get_data(&self) -> i32 {
self.value
}
}
// 实现MyTrait的结构体示例2
struct Example2 {
value: i32,
}
impl MyTrait for Example2 {
fn get_data(&self) -> i32 {
self.value
}
}
fn main() {
let ex1 = Example1 { value: 10 };
let ex2 = Example2 { value: 20 };
let result = combine_data(&ex1, &ex2);
println!("Combined data: {}", result.data);
}
生命周期、泛型及trait bounds协同工作的理解
- 泛型:泛型在Rust中允许我们编写可以处理多种类型的代码,提高代码复用性。在上述函数
combine_data
中,T1
和T2
是泛型类型参数,这使得函数可以接受不同类型的参数,只要这些类型满足指定的trait bounds
。 - trait bounds:
T1: MyTrait
和T2: MyTrait
表示类型参数T1
和T2
必须实现MyTrait
。这确保了在函数中调用get_data
方法是合法的,因为只有实现了MyTrait
的类型才有这个方法。 - 生命周期:
'a
和'b
是生命周期参数。在函数签名combine_data<T1: 'a + MyTrait, T2: 'b + MyTrait, 'a, 'b>(arg1: &'a T1, arg2: &'b T2)
中,arg1
的生命周期为'a
,arg2
的生命周期为'b
。这两个生命周期参数明确了函数参数的有效作用域。
在复杂场景下,生命周期与泛型及trait bounds协同工作来确保内存安全。泛型使得代码可以处理多种类型,trait bounds限制这些类型必须具备某些功能,而生命周期参数确保引用在其有效作用域内保持合法,避免悬垂引用等内存安全问题。例如,在combine_data
函数中,arg1
和arg2
的生命周期被明确指定,返回的NewStruct
中的数据是从这些引用中获取的,所以这些引用必须在函数返回后仍然有效,这通过生命周期参数来保证。