Rust 练习册 :低功耗嵌入式游戏开发
摘要:Rust凭借其零成本抽象、内存安全和并发特性,成为嵌入式开发的理想选择。本文通过游戏开发场景展示了Rust在嵌入式领域的优势:1) 利用元组结构体实现高效除法和曼哈顿距离计算;2) 通过迭代器实现惰性求值的数据处理;3) 借助泛型编程提升代码复用性。这些特性完美应对了嵌入式系统面临的内存限制、性能要求和实时性挑战,使其在游戏开发、IoT设备等场景中展现出强大潜力。Rust的工具链和编译时安全
在物联网和嵌入式系统蓬勃发展的今天,Rust 作为一种系统级编程语言正变得越来越重要。它的零成本抽象、内存安全和并发性使其成为嵌入式开发的理想选择。今天,我们将通过几个小游戏开发中的常见任务来探索 Rust 在嵌入式领域的强大功能。
嵌入式系统的挑战
嵌入式系统通常面临以下挑战:
- 内存资源有限
- 处理能力受限
- 功耗要求严格
- 需要高可靠性和实时响应
Rust 的设计哲学恰好能很好地应对这些挑战。
任务一:高效的除法和取模运算
在游戏中,我们经常需要进行除法和取模运算,比如计算精灵在网格中的位置。在一个资源受限的环境中,能够同时获得商和余数会大大提高效率。
pub fn divmod(dividend: i16, divisor: i16) -> (i16, i16) {
(dividend / divisor, dividend % divisor)
}
这是一个简单却非常实用的函数。通过一次计算同时返回商和余数,避免了重复计算。在嵌入式系统中,每一次 CPU 周期都很宝贵。
元组的力量
pub fn divmod(dividend: i16, divisor: i16) -> (i16, i16) {
(dividend / divisor, dividend % divisor)
}
Rust 的元组(tuple)特性让我们可以轻松地返回多个值,而不需要定义专门的结构体。这对于嵌入式开发尤其有价值,因为它减少了内存分配和代码复杂度。
任务二:迭代器的魅力
在游戏开发中,我们经常需要处理序列数据。Rust 的迭代器提供了一种高效且惰性求值的方式来处理数据流。
pub fn evens<T>(iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
iter.step_by(2)
}
这个函数的作用是从给定的迭代器中选出偶数位置的元素。这看起来简单,但它展示了 Rust 迭代器的强大之处:
泛型和 trait bounds
pub fn evens<T>(iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
iter.step_by(2)
}
通过使用泛型和 trait bounds,这个函数可以处理任何类型的迭代器,无论是数字、字符串还是自定义对象。这种灵活性和性能的结合正是 Rust 的魅力所在。
惰性求值
Rust 的迭代器是惰性求值的,这意味着它们只在需要时才进行计算。在内存受限的嵌入式系统中,这种特性可以显著减少内存占用。
任务三:曼哈顿距离计算
在网格游戏中,计算两点间的距离是一项基本操作。欧几里得距离虽然直观,但在网格中更常用的是曼哈顿距离。
pub struct Position(pub i16, pub i16);
impl Position {
pub fn manhattan(&self) -> i16 {
self.0.abs() + self.1.abs()
}
}
元组结构体
pub struct Position(pub i16, pub i16);
我们使用了元组结构体(tuple struct)来表示位置。这是一种轻量级的数据结构,非常适合嵌入式环境。pub 关键字使字段公开,方便直接访问。
方法实现
impl Position {
pub fn manhattan(&self) -> i16 {
self.0.abs() + self.1.abs()
}
}
曼哈顿距离的计算非常简单:两个坐标轴差值的绝对值之和。在游戏 AI 中,这个函数可以用来估算移动成本或检测碰撞。
完整代码展示
// This stub file contains items which aren't used yet; feel free to remove this module attribute
// to enable stricter warnings.
#![allow(unused)]
pub fn divmod(dividend: i16, divisor: i16) -> (i16, i16) {
(dividend / divisor, dividend % divisor)
}
pub fn evens<T>(iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
iter.step_by(2)
}
pub struct Position(pub i16, pub i16);
impl Position {
pub fn manhattan(&self) -> i16 {
self.0.abs() + self.1.abs()
}
}
测试验证
通过测试用例我们可以看到各种方法的行为:
mod divmod {
//! tests of divmod
//!
//! note that we're only testing positive quantities; no need to get into the mod/rem distinction
use low_power_embedded_game::divmod;
#[test]
fn example() {
assert_eq!(divmod(10, 3), (3, 1));
}
#[test]
fn powerup() {
assert_eq!(divmod(100, 3), (33, 1));
}
#[test]
fn less() {
assert_eq!(divmod(3, 10), (0, 3));
}
#[test]
fn eq() {
assert_eq!(divmod(3, 3), (1, 0));
}
#[test]
fn multiple() {
assert_eq!(divmod(9, 3), (3, 0));
}
}
mod evens {
use low_power_embedded_game::evens;
#[test]
fn simple_i32() {
let out: Vec<i32> = evens(0..).take(5).collect();
assert_eq!(out, &[0, 2, 4, 6, 8]);
}
#[test]
fn reverse_i32() {
let out: Vec<i32> = evens((0..=10).rev()).collect();
assert_eq!(out, &[10, 8, 6, 4, 2, 0]);
}
#[test]
fn offset_i32() {
let out: Vec<i32> = evens(1..).take(5).collect();
assert_eq!(out, &[1, 3, 5, 7, 9]);
}
#[test]
fn strs() {
let input = "You really must never be above joking.".split_whitespace();
let expected: Vec<_> = "You must be joking.".split_whitespace().collect();
let out: Vec<_> = evens(input).collect();
assert_eq!(out, expected);
}
}
mod manhattan {
use low_power_embedded_game::Position;
#[test]
fn origin() {
assert_eq!(Position(0, 0).manhattan(), 0);
}
#[test]
fn q1_unit() {
assert_eq!(Position(1, 1).manhattan(), 2);
}
#[test]
fn q2_unit() {
assert_eq!(Position(1, -1).manhattan(), 2);
}
#[test]
fn q3_unit() {
assert_eq!(Position(-1, -1).manhattan(), 2);
}
#[test]
fn q4_unit() {
assert_eq!(Position(-1, 1).manhattan(), 2);
}
#[test]
fn relative_prime() {
assert_eq!(Position(30, 70).manhattan(), 100);
}
}
Rust 在嵌入式开发中的优势
1. 零成本抽象
pub fn evens<T>(iter: impl Iterator<Item = T>) -> impl Iterator<Item = T> {
iter.step_by(2)
}
Rust 的迭代器在编译后通常会被优化成与手写循环一样高效的机器码。
2. 内存安全
Rust 在编译时就能防止空指针解引用、缓冲区溢出等常见错误,这对于需要高可靠性的嵌入式系统至关重要。
3. 无垃圾回收
与 Go 或 Java 等语言不同,Rust 不需要垃圾回收器,这对于实时性要求高的嵌入式系统非常重要。
4. 优秀的工具链
Rust 提供了出色的包管理器 Cargo,以及丰富的生态系统,大大简化了嵌入式开发的复杂性。
实际应用场景
这些技术在实际的嵌入式开发中有广泛应用:
- 游戏开发:处理游戏对象的位置、动画和碰撞检测
- IoT 设备:传感器数据处理和通信协议实现
- 机器人控制:路径规划和运动控制算法
- 汽车电子:ADAS 系统和车载娱乐系统
- 航空航天:飞行控制系统和卫星数据处理
总结
通过这个练习,我们看到了 Rust 在嵌入式开发中的巨大潜力:
- 元组提供了简洁的多值返回机制
- 迭代器实现了高效的数据处理流水线
- 结构体和元组结构体提供了灵活的数据建模方式
- trait system支持了强大的泛型编程
Rust 不仅是一门系统编程语言,更是现代嵌入式开发的优秀选择。它能够在保证内存安全的同时,提供与 C/C++ 相媲美的性能。
随着 Rust 在嵌入式领域的生态不断完善,我们可以期待看到更多基于 Rust 的创新嵌入式产品出现。
在下一篇文章中,我们将继续探索 Rust 的更多强大功能!
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐
所有评论(0)