Install
openclaw skills install @thcjp/rust-toolkit-freeopenclaw skills install @thcjp/rust-toolkit-freeRust 工具包免费版是面向个人开发者的 Rust 优选实践助手。覆盖 Rust 开发中最常见的所有权、借用、生命周期陷阱,提供即查即用的修复建议与代码规范,帮助开发者写出安全可靠的系统级代码.
检测所有权转移、借用冲突、可变与不可变借用混用等常见问题.
处理: 解析所有权与借用的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回所有权与借用的响应数据,包含状态码、结果和日志.
input_params参数,支持创建/查询/导出操作指导何时需要显式生命周期标注,何时可以省略(生命周期省略规则).
处理: 解析生命周期标注的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回生命周期标注的响应数据,包含状态码、结果和日志.
input_params参数,支持创建/查询/导出操作用input_params参数进行配置.
处理: 解析核心功能执行的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回核心功能执行的响应数据,包含状态码、结果和日志.
input_params参数,支持创建/查询/导出操作
能力覆盖范围:本skill的核心能力覆盖以下场景关键词:Rust、开发优选实践助手、避免所有权、借用与生命周期常、见陷阱、适合个人学习、免费版、面向个人开发者与、学习者、核心能力、所有权与借用陷阱、生命周期标注指导、错误处理、Result、Option、优选实践、并发编程、async、await、channels、Mutex、Trait、与泛型使用规范、Cargo、项目配置、常见编译错误解读等.Result<T, E> 与 Option<T> 的正确使用,? 操作符的优选实践.
处理: 解析错误处理的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回错误处理的响应数据,包含状态码、结果和日志.
async/await、channels、Mutex/RwLock、Arc 的使用场景与陷阱.
处理: 解析并发编程的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回并发编程的响应数据,包含状态码、结果和日志.
Trait 定义与实现、泛型约束、Trait Object(dyn)vs 泛型参数.
处理: 解析Trait 与泛型的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回Trait 与泛型的响应数据,包含状态码、结果和日志.
Cargo.toml 配置、依赖管理、feature flags、workspace.
处理: 解析Cargo 配置的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回Cargo 配置的响应数据,包含状态码、结果和日志.
将 Rust 编译器复杂的错误信息翻译为可理解的修复建议.
处理: 解析编译错误解读的输入参数,完成核心逻辑,返回结构化响应. 输出: 返回编译错误解读的响应数据,包含状态码、结果和日志.
Rust 中最常见的编译错误之一:可变与不可变借用冲突.
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| input | string | 是 | Rust工具包-免费版处理的输入数据或指令 |
| options | object | 否 | 附加配置选项,如模式选择、格式偏好等 |
| callback_url | string | 否 | 异步处理完成后的回调通知URL |
// 错误写法 - 同时存在可变和不可变借用
fn main() {
let mut data = vec![1, 2, 3];
let first = &data[0]; // 不可变借用
data.push(4); // 错误!可变借用冲突
println!("{}", first); // first 还在使用中
}
// ...
// 正确写法 - 借用在使用后结束
fn main() {
let first = &data[0];
println!("{}", first); // 借用在此结束
data.push(4); // 现在可以可变借用了
}
// ...
// 或使用拷贝
fn main() {
let first = data[0]; // 拷贝值,不是借用
data.push(4); // 没问题
println!("{}", first);
}
理解何时需要显式标注生命周期.
// 生命周期省略规则适用的场景 - 无需标注
fn first_word(s: &str) -> &str {
// 编译器自动推断:输入引用的生命周期 = 输出引用的生命周期
let bytes = s.as_bytes();
for (i, &byte) in bytes.iter().enumerate() {
if byte == b' ' {
return &s[0..i];
}
}
&s[..]
}
// ...
// 需要显式标注的场景 - 多个输入引用
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
// 返回值的生命周期取决于两个输入中较短的那个
if s1.len() > s2.len() {
s1
} else {
s2
}
}
// ...
// 结构体中的生命周期
struct Excerpt<'a> {
part: &'a str, // 结构体持有引用必须标注生命周期
}
使用 Result 和 ? 操作符进行错误传播.
use std::fs;
use std::io;
use std::num::ParseIntError;
// ...
// 错误写法 - 使用 unwrap/expect 在生产代码中
fn read_config() -> i32 {
let content = fs::read_to_string("config.txt").unwrap(); // 危险!
let value: i32 = content.trim().parse().unwrap(); // 危险!
value
}
// ...
// 正确写法 - 使用 Result 和 ? 传播错误
fn read_config() -> Result<i32, Box<dyn std::error::Error>> {
Ok(value)
}
// ...
// 自定义错误类型
#[derive(Debug)]
enum ConfigError {
Io(io::Error),
Parse(ParseIntError),
}
// ...
impl From<io::Error> for ConfigError {
fn from(e: io::Error) -> Self { ConfigError::Io(e) }
}
impl From<ParseIntError> for ConfigError {
fn from(e: ParseIntError) -> Self { ConfigError::Parse(e) }
}
// ...
fn read_config_typed() -> Result<i32, ConfigError> {
Ok(value)
}
以下场景Rust工具包-免费版不适合处理:
需要代码生成、编程辅助、调试测试、开发部署时使用。不适用于非本工具能力范围的需求.
// 1. 可变借用冲突 -> 确保借用不重叠
let mut v = vec![1, 2, 3];
let r = &v[0]; // 不可变借用开始
// v.push(4); // 错误!
println!("{}", r); // 借用结束
v.push(4); // 现在可以了
// ...
// 2. 字符串拼接用 format! -> 不要用 + (需 &String)
let s1 = String::from("Hello");
let s2 = String::from("World");
let s3 = format!("{} {}", s1, s2); // 推荐
// ...
// 3. 遍历时修改 -> 使用索引或 drain
let mut v = vec![1, 2, 3, 4];
let mut i = 0;
while i < v.len() {
if v[i] % 2 == 0 {
v.remove(i);
} else {
i += 1;
}
}
// ...
// 4. 用 clone 替代引用 -> 简化所有权(性能允许时)
fn process(data: Vec<i32>) -> Vec<i32> { // 取得所有权
data.iter().map(|x| x * 2).collect()
}
let original = vec![1, 2, 3];
let result = process(original.clone()); // clone 保留原始数据
// ...
// 5. 用 Cow 处理可能借用的数据
use std::borrow::Cow;
fn process(input: &str) -> Cow<str> {
if input.contains("bad") {
Cow::Owned(input.replace("bad", "good")) // 新分配
} else {
Cow::Borrowed(input) // 零拷贝
}
}
# Cargo.toml
[package]
name = "my-project"
version = "0.1.0"
edition = "2021"
# ...
[dependencies]
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
# ...
[profile.release]
opt-level = 3
lto = true
codegen-units = 1
| 陷阱 | 错误写法 | 正确写法 |
|---|---|---|
| 借用冲突 | 同时 &mut 和 & | 借用不重叠 |
| 字符串拼接 | s1 + s2 | format!("{}{}", s1, s2) |
| 遍历时删除 | for x in &v { v.remove() } | 用索引或 retain |
| unwrap 滥用 | .unwrap() | ? 操作符 |
| 所有权困惑 | 到处 .clone() | 理解所有权传递 |
| 生命周期 | 全部显式标注 | 先省略,编译器提示再标注 |
| Trait Object | 滥用 dyn | 优先用泛型 |
| 闭包捕获 | move 误用 | 按需使用 move |
# clippy 配置
# .clippy.toml
msrv = "1.70.0"
# ...
# 运行 clippy
# cargo clippy -- -W clippy::all -W clippy::pedantic
& 借用:不需要所有权时用引用,避免不必要的 clone? 传播错误:不要滥用 unwrap(),生产代码用 Result + ?impl Trait),灵活性优先用 dyn TraitCow 优化拷贝:可能不需要拷贝的场景使用 Cow<str> 或 Cow<[T]>cargo clippy,修复所有警告retain 过滤:需要删除元素时用 v.retain(|x| condition) 而非循环 removeA: 这是最常见的借用冲突。确保不可变借用在可变借用之前结束使用。方法:1) 提前使用完不可变借用;2) 拷贝值而非借用;3) 重构代码结构减少借用重叠.
String 什么时候用 &str?A: 函数参数优先用 &str(更通用,接受 &String 和 &str)。需要所有权或需要修改时用 String。结构体字段通常用 String(拥有数据)。返回值如果引用输入参数用 &str,否则用 String.
Box<dyn Trait> 和 impl Trait 的区别?A: impl Trait 是静态分发(编译时确定类型,零开销,但生成多份代码)。Box<dyn Trait> 是动态分发(运行时确定,有虚函数表开销,但代码体积小)。性能优先用 impl Trait,需要集合存储不同类型或递归类型用 Box<dyn Trait>.
A: async 函数返回 impl Future<Output = T>。通常不需要显式标注,让编译器推断。如果需要 dyn 异步 trait,使用 Pin<Box<dyn Future<Output = T> + Send>> 或使用 async-trait 宏.
| 依赖项 | 类型 | 是否必需 | 获取方式 |
|---|---|---|---|
| Rust | 编译器 | 必需 | rustup 安装 |
| Cargo | 包管理 | 必需 | 随 Rust 安装 |
| Clippy | Lint工具 | 推荐 | rustup component add clippy |
| rustfmt | 格式化 | 推荐 | rustup component add rustfmt |
| LLM API | API | 必需 | 由Agent内置LLM提供 |
{
"input": "示例输入",
"output": "处理结果"
}
处理结果以结构化格式返回, 包含状态码、消息和数据字段.