Rust 程序设计语言学习——泛型、Trait和生命周期
创作时间:
作者:
@小白创作中心
Rust 程序设计语言学习——泛型、Trait和生命周期
引用
CSDN
1.
https://blog.csdn.net/tyyj90/article/details/140032029
Rust是一门系统级编程语言,以其内存安全和并发安全著称。在Rust中,泛型、Trait和生命周期是三个核心概念,它们共同帮助开发者编写更安全、更灵活的代码。本文将详细介绍这些概念的基本原理、使用方法和实际应用,通过具体的代码示例帮助读者理解。
一、泛型
泛型是Rust中处理重复概念的重要工具。通过泛型,我们可以为函数签名或结构体创建定义,使其能够用于多种不同的具体数据类型。
1.1 在函数定义中使用泛型
在函数签名中使用泛型,可以使得代码更具适应性和复用性。例如:
fn add_impl<T>(num1: T, num2: T) -> T
where
T: std::ops::Add<Output = T> + Copy,
{
num1 + num2
}
fn main() {
let a = 3.0f32;
let b = 4.5f32;
let ret = add_impl(a, b);
println!("The result of {} + {} is {}", a, b, ret);
let a1 = 3;
let b1 = 4;
let ret1 = add_impl(a1, b1);
println!("The result of {} + {} is {}", a1, b1, ret1);
}
运行结果
The result of 3 + 4.5 is 7.5
The result of 3 + 4 is 7
1.2 结构体、方法定义中的泛型
同样可以在结构体中使用泛型,以创建更灵活的数据结构。例如:
struct Box<T> {
width: T,
height: T,
}
impl<T> Box<T> {
fn area(&self) -> T
where
T: std::ops::Mul<Output = T> + Copy,
{
self.width * self.height
}
}
impl<T> Box<T> {
fn new(width: T, height: T) -> Self {
Box { width, height }
}
}
fn main() {
let int_box = Box::new(10, 20);
println!("The area of the integer box is: {}", int_box.area());
let float_box = Box::new(10.5, 20.3);
println!("The area of the float box is: {}", float_box.area());
}
运行结果
The area of the integer box is: 200
The area of the float box is: 213.15
1.3 枚举定义中的泛型
枚举也可以包含泛型数据类型。例如标准库中的Option<T>枚举:
enum Option<T> {
Some(T),
None,
}
1.4 泛型代码的性能
Rust通过编译时的单态化(monomorphization)过程来优化泛型代码的性能。例如:
let integer = Some(5);
let float = Some(5.0);
编译器会生成类似以下的单态化代码:
enum Option_i32 {
Some(i32),
None,
}
enum Option_f64 {
Some(f64),
None,
}
fn main() {
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
}
二、Trait
Trait类似于其他语言中的接口,用于定义类型的行为。例如:
pub trait Animal {
fn speak(&self);
fn name(&self) -> &str;
}
struct Dog {
name: String,
}
impl Animal for Dog {
fn speak(&self) {
println!("Woof!");
}
fn name(&self) -> &str {
&self.name
}
}
struct Cat {
name: String,
}
impl Animal for Cat {
fn speak(&self) {
println!("Meow!");
}
fn name(&self) -> &str {
&self.name
}
}
fn animal_sound<T: Animal>(animal: &T) {
println!("{} says: ", animal.name());
animal.speak();
}
fn main() {
let dog = Dog {
name: "Rex".to_string(),
};
let cat = Cat {
name: "Whiskers".to_string(),
};
animal_sound(&dog);
animal_sound(&cat);
}
运行结果
Rex says:
Woof!
Whiskers says:
Meow!
三、生命周期
生命周期是Rust中确保引用安全的重要机制。例如:
fn main() {
let a;
{
let b = 1;
a = &b;
println!("a: {a} b: {b}");
}
println!("a: {a}");
}
编译报错信息:
Compiling playground v0.0.1 (/playground)
error[E0597]: `b` does not live long enough
--> src/main.rs:6:13
|
5 | let b = 1;
| - binding `b` declared here
6 | a = &b;
| ^^ borrowed value does not live long enough
7 | println!("a: {a} b: {b}");
8 | }
| - `b` dropped here while still borrowed
9 |
10 | println!("a: {a}");
| --- borrow later used here
For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` (bin "playground") due to 1 previous error
3.1 生命周期避免了悬垂引用
生命周期的主要目标是避免悬垂引用。例如:
fn main() {
let a; //---------+-- 'a
// |
{ // |
let b = 1; //-+-- 'b |
a = &b; // | |
println!("a: {a} b: {b}"); // | |
} //-+ |
// |
println!("a: {a}"); // |
} //---------+
3.2 函数中的泛型生命周期
例如:
fn max<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
if (*x) > (*y) {
x
} else {
y
}
}
fn main() {
let a = 10;
let b = 20;
println!("max: {}", max(&a, &b));
}
运行结果
max: 20
3.3 函数签名中的生命周期注解
生命周期注解的语法:
&i32 // 引用
&'a i32 // 带有显式生命周期的引用
&'a mut i32 // 带有显式生命周期的可变引用
3.4 结构体和方法定义中的生命周期注解
例如:
struct Message<'a> {
content: &'a str,
}
impl<'a> Message<'a> {
fn print(&self) {
println!("The message is: {}", self.content);
}
}
fn main() {
let text = "Hello, Rust!".to_string();
let message = Message { content: &text };
message.print();
}
运行结果
The message is: Hello, Rust!
3.5 生命周期省略
Rust编译器采用三条规则来判断引用何时不需要明确的注解:
- 每个引用参数都分配一个生命周期参数。
- 如果只有一个输入生命周期参数,它被赋予所有输出生命周期参数。
- 如果方法有多个输入生命周期参数并且其中一个参数是
&self或&mut self,则所有输出生命周期参数被赋予self的生命周期。
3.6 静态生命周期
例如:
let s: &'static str = "I have a static lifetime.";
3.7 结合泛型类型参数、trait bounds 和生命周期
例如:
trait Append {
fn append(&mut self, other: &str);
}
impl Append for String {
fn append(&mut self, other: &str) {
self.push_str(other);
}
}
struct Appender<'a, T: Append> {
item: &'a mut T,
}
impl<'a, T: Append> Appender<'a, T> {
fn add_content(&mut self, other: &str) {
self.item.append(other);
}
}
fn main() {
let mut text = String::from("Hello, ");
let mut appender = Appender { item: &mut text };
appender.add_content("world!");
println!("{}", text);
}
运行结果
Hello, world!
参考链接
- Rust 官方网站:https://www.rust-lang.org/zh-CN
- Rust 官方文档:https://doc.rust-lang.org/
- Rust Play:https://play.rust-lang.org/
- 《Rust 程序设计语言》
热门推荐
促进甲状腺疾病早筛早治 甲状腺健康公益行项目在京启动
【宋韵流觞】临安城考古│李蜀蕾:南宋御街古今地望考析
CAD图纸导出为PDF的详细步骤与技巧指南
Deepseek掀起了一场伟大的博弈——纪念《伟大的博弈》中文版出版二十周年
菊苣的多种用途:从饲料到药用的全面解析
金银花的副作用与禁忌是什么
十部华语悬疑佳作:烧脑剧情,令人拍案叫绝!
好心帮忙出意外,风险责任谁来担?
新闻学专业就业方向与就业前景怎么样
A级景区总量居全省第一 甘孜“文旅之州”建设见势成效
你的血管正在悄悄长斑变硬!这样做,“斑块”可能缩小甚至消失……
湖北旅游黄鹤楼东湖一日游攻略
房屋买卖合同中的房屋交接
咳嗽却开鼻喷雾剂?揭开医生的"神操作"
国内牛肉价格创历史新低,国际价格却‘牛气十足’,究竟为何?
掏耳朵后耳朵感觉堵住了听不清怎么办
专家:不要频繁用棉签挖耳,耳屎堵住应去医院而不是去采耳
肚脐上方痛怎么回事
C语言中绝对值函数的多种调用方式详解
优化保险理赔服务系统:提升效率与满意度的关键路径
优化保险理赔服务系统:提升效率与满意度的关键路径
研究餐具在不同文化中的差异,包括餐桌礼仪、传统设计以及某些餐具的重要性
扬州6日旅游攻略路线,如何深度体验这座城市的魅力?
DevC++运行C语言代码入门指南
如何在银行办理信用卡还款宽限期?
如何用C语言编写PID控制器
长风衣的4种搭配技巧,助你打造优雅时尚的早春造型。
疫苗选国产还是进口?——聊聊乙肝疫苗那点事儿
楼市回暖!多地新房市场成交持续回升 二手房市场企稳效果明显
美元霸权的根源:背后的政治经济博弈