示例1:解析配置
rust
use std::fs;
use std::num::ParseIntError;
#[derive(Debug)]
struct Config {
port: u16,
host: String,
timeout: u64,
}
#[derive(Debug)]
enum ConfigError {
ReadFile(String),
ParsePort(ParseIntError),
ParseTimeout(ParseIntError),
MissingHost,
}
fn load_config(path: &str) -> Result<Config, ConfigError> {
// 读取文件
let content = fs::read_to_string(path)
.map_err(|e| ConfigError::ReadFile(e.to_string()))?;
// 解析配置
let mut port = None;
let mut host = None;
let mut timeout = None;
for line in content.lines() {
if let Some((key, value)) = line.split_once('=') {
let key = key.trim();
let value = value.trim();
match key {
"PORT" => {
port = Some(value.parse()
.map_err(ConfigError::ParsePort)?);
}
"HOST" => {
host = Some(value.to_string());
}
"TIMEOUT" => {
timeout = Some(value.parse()
.map_err(ConfigError::ParseTimeout)?);
}
_ => {}
}
}
}
Ok(Config {
port: port.ok_or(ConfigError::MissingHost)?,
host: host.ok_or(ConfigError::MissingHost)?,
timeout: timeout.unwrap_or(30), // 默认值
})
}
fn main() {
match load_config("config.txt") {
Ok(config) => {
println!("配置加载成功: {:?}", config);
println!("Server running on {}:{} 超时{}", config.host, config.port,config.timeout);
}
Err(e) => {
println!("配置加载失败: {:?}", e);
}
}
}
config.txt文件内容为:
PORT=8080
HOST=127.0.0.1
TIMEOUT=60
输出结果为:

示例2:用户输入验证
rust
use std::io::{self, Write};
fn read_number(prompt: &str) -> Result<i32, String> {
print!("{}", prompt);
io::stdout().flush().unwrap();
let mut input = String::new();
io::stdin().read_line(&mut input)
.map_err(|e| format!("读取输入失败: {}", e))?;
let trimmed = input.trim();
if trimmed.is_empty() {
return Err("输入不能为空".to_string());
}
trimmed.parse()
.map_err(|_| format!("'{}' 不是有效的数字", trimmed))
}
fn main() {
// 使用循环重试
let number = loop {
match read_number("请输入一个数字: ") {
Ok(n) => break n,
Err(e) => {
println!("错误: {},请重新输入", e);
}
}
};
println!("你输入的数字是: {}", number);
}
验证结果:

示例3:链式调用与 Option
rust
#[derive(Debug)]
struct User {
id: u32,
name: String,
email: Option<String>,
age: Option<u32>,
}
impl User {
fn new(id: u32, name: &str) -> Self {
User {
id,
name: name.to_string(),
email: None,
age: None,
}
}
// 设置邮箱
fn set_email(&mut self, email: &str) -> &mut Self {
self.email = Some(email.to_string());
self
}
// 设置年龄
fn set_age(&mut self, age: u32) -> &mut Self {
self.age = Some(age);
self
}
// 获取年龄显示信息
fn age_info(&self) -> String {
self.age
.map(|a| format!("{} 岁", a))
.unwrap_or_else(|| "年龄未设置".to_string())
}
// 获取邮箱显示信息
fn email_info(&self) -> String {
self.email
.as_ref()
.map(|e| format!("邮箱: {}", e))
.unwrap_or_else(|| "未设置邮箱".to_string())
}
}
fn main() {
let mut user = User::new(1, "Alice");
user.set_email("alice@example.com")
.set_age(25);
println!("用户: {}", user.name);
println!("{}", user.email_info());
println!("{}", user.age_info());
// 使用 Option 处理可选字段
let maybe_age = user.age;
if let Some(age) = maybe_age {
if age >= 18 {
println!("{} 是成年人", user.name);
}
}
}
结果:

示例4:桌面图标自动整理
rust
use std::fs;
use std::path::{Path, PathBuf};
use std::io::{self, Write};
use std::time::SystemTime;
use serde::{Deserialize, Serialize};
/// 获取当前时间戳字符串
fn get_timestamp() -> String {
let duration = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
let secs = duration.as_secs();
format!("{}", secs)
}
/// 获取文件时间戳字符串(用于文件名)
fn get_file_timestamp() -> String {
let duration = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
let secs = duration.as_secs();
format!("{}", secs)
}
/// 分类规则配置
#[derive(Debug, Serialize, Deserialize, Clone)]
struct CategoryRule {
/// 分类名称
name: String,
/// 文件夹名称
folder_name: String,
/// 文件扩展名列表
extensions: Vec<String>,
}
/// 默认分类规则
fn default_rules() -> Vec<CategoryRule> {
vec![
CategoryRule {
name: "文档".to_string(),
folder_name: "文档".to_string(),
extensions: vec![
"doc".to_string(), "docx".to_string(), "pdf".to_string(),
"txt".to_string(), "xls".to_string(), "xlsx".to_string(),
"ppt".to_string(), "pptx".to_string(), "md".to_string(),
"csv".to_string(), "rtf".to_string(), "odt".to_string(),
],
},
CategoryRule {
name: "图片".to_string(),
folder_name: "图片".to_string(),
extensions: vec![
"jpg".to_string(), "jpeg".to_string(), "png".to_string(),
"gif".to_string(), "bmp".to_string(), "svg".to_string(),
"ico".to_string(), "webp".to_string(), "tiff".to_string(),
"raw".to_string(), "psd".to_string(),
],
},
CategoryRule {
name: "视频".to_string(),
folder_name: "视频".to_string(),
extensions: vec![
"mp4".to_string(), "avi".to_string(), "mkv".to_string(),
"mov".to_string(), "wmv".to_string(), "flv".to_string(),
"webm".to_string(), "m4v".to_string(), "rmvb".to_string(),
"rm".to_string(), "3gp".to_string(),
],
},
CategoryRule {
name: "音频".to_string(),
folder_name: "音频".to_string(),
extensions: vec![
"mp3".to_string(), "wav".to_string(), "flac".to_string(),
"aac".to_string(), "ogg".to_string(), "wma".to_string(),
"m4a".to_string(), "ape".to_string(), "mid".to_string(),
],
},
CategoryRule {
name: "压缩包".to_string(),
folder_name: "压缩包".to_string(),
extensions: vec![
"zip".to_string(), "rar".to_string(), "7z".to_string(),
"tar".to_string(), "gz".to_string(), "bz2".to_string(),
"xz".to_string(), "iso".to_string(), "dmg".to_string(),
],
},
CategoryRule {
name: "程序".to_string(),
folder_name: "程序".to_string(),
extensions: vec![
"exe".to_string(), "msi".to_string(), "bat".to_string(),
"cmd".to_string(), "lnk".to_string(), "appx".to_string(),
"appxbundle".to_string(),
],
},
CategoryRule {
name: "代码".to_string(),
folder_name: "代码".to_string(),
extensions: vec![
"py".to_string(), "js".to_string(), "ts".to_string(),
"html".to_string(), "css".to_string(), "java".to_string(),
"cpp".to_string(), "c".to_string(), "h".to_string(),
"rs".to_string(), "go".to_string(), "rb".to_string(),
"php".to_string(), "json".to_string(), "xml".to_string(),
"yaml".to_string(), "yml".to_string(), "toml".to_string(),
],
},
]
}
/// 文件移动记录(用于撤销)
#[derive(Debug, Serialize, Deserialize)]
struct MoveRecord {
source: PathBuf,
destination: PathBuf,
timestamp: String,
}
/// 撤销日志
#[derive(Debug, Serialize, Deserialize)]
struct UndoLog {
records: Vec<MoveRecord>,
}
impl UndoLog {
fn new() -> Self {
UndoLog {
records: Vec::new(),
}
}
fn add_record(&mut self, source: PathBuf, destination: PathBuf) {
self.records.push(MoveRecord {
source,
destination,
timestamp: get_timestamp(),
});
}
fn save(&self, path: &Path) -> io::Result<()> {
let json = serde_json::to_string_pretty(self)?;
fs::write(path, json)?;
Ok(())
}
fn load(path: &Path) -> io::Result<Self> {
let content = fs::read_to_string(path)?;
let log: UndoLog = serde_json::from_str(&content)?;
Ok(log)
}
fn is_empty(&self) -> bool {
self.records.is_empty()
}
fn clear(&mut self) {
self.records.clear();
}
}
/// 获取桌面路径
fn get_desktop_path() -> PathBuf {
dirs::desktop_dir().expect("无法获取桌面路径")
}
/// 获取配置目录
fn get_config_dir() -> PathBuf {
let config_dir = dirs::config_dir().expect("无法获取配置目录");
config_dir.join("windows-tubiao")
}
/// 获取配置文件路径
fn get_config_path() -> PathBuf {
get_config_dir().join("rules.json")
}
/// 获取撤销日志路径
fn get_undo_log_path() -> PathBuf {
get_config_dir().join("undo_log.json")
}
/// 加载分类规则
fn load_rules() -> Vec<CategoryRule> {
let config_path = get_config_path();
if config_path.exists() {
match fs::read_to_string(&config_path) {
Ok(content) => {
match serde_json::from_str(&content) {
Ok(rules) => {
println!("已从配置文件加载分类规则");
return rules;
}
Err(e) => {
eprintln!("配置文件解析失败: {}, 使用默认规则", e);
}
}
}
Err(e) => {
eprintln!("读取配置文件失败: {}, 使用默认规则", e);
}
}
}
default_rules()
}
/// 保存分类规则
fn save_rules(rules: &[CategoryRule]) -> io::Result<()> {
let config_dir = get_config_dir();
fs::create_dir_all(&config_dir)?;
let config_path = get_config_path();
let json = serde_json::to_string_pretty(rules)?;
fs::write(config_path, json)?;
Ok(())
}
/// 分类文件
fn categorize_file(file_path: &Path, rules: &[CategoryRule]) -> Option<String> {
if let Some(ext) = file_path.extension() {
let ext_str = ext.to_string_lossy().to_lowercase();
for rule in rules {
if rule.extensions.contains(&ext_str) {
return Some(rule.folder_name.clone());
}
}
}
None
}
/// 扫描桌面文件
fn scan_desktop_files(desktop_path: &Path) -> Vec<PathBuf> {
let mut files = Vec::new();
if let Ok(entries) = fs::read_dir(desktop_path) {
for entry in entries {
if let Ok(entry) = entry {
let path = entry.path();
// 只处理文件,跳过目录和系统文件
if path.is_file() {
// 跳过隐藏文件
if let Some(name) = path.file_name() {
let name_str = name.to_string_lossy();
if !name_str.starts_with('.') && !name_str.starts_with('$') {
files.push(path);
}
}
}
}
}
}
files
}
/// 执行整理
fn organize_desktop(rules: &[CategoryRule]) -> io::Result<UndoLog> {
let desktop_path = get_desktop_path();
let files = scan_desktop_files(&desktop_path);
if files.is_empty() {
println!("桌面上没有需要整理的文件");
return Ok(UndoLog::new());
}
println!("\n扫描到 {} 个文件,开始整理...\n", files.len());
let mut undo_log = UndoLog::new();
let mut categorized_count = 0;
let mut uncategorized_count = 0;
for file_path in &files {
if let Some(category) = categorize_file(file_path, rules) {
// 创建分类文件夹
let category_dir = desktop_path.join(&category);
if !category_dir.exists() {
fs::create_dir_all(&category_dir)?;
}
// 移动文件
let file_name = file_path.file_name().unwrap();
let dest_path = category_dir.join(file_name);
// 如果目标文件已存在,添加时间戳避免覆盖
let final_dest = if dest_path.exists() {
let stem = file_path.file_stem().unwrap().to_string_lossy();
let ext = file_path.extension().unwrap().to_string_lossy();
let timestamp = get_file_timestamp();
let new_name = format!("{}_{}.{}", stem, timestamp, ext);
category_dir.join(new_name)
} else {
dest_path
};
match fs::rename(file_path, &final_dest) {
Ok(_) => {
undo_log.add_record(file_path.clone(), final_dest);
categorized_count += 1;
println!(" [{}] -> {}/", file_path.file_name().unwrap().to_string_lossy(), category);
}
Err(e) => {
eprintln!(" 移动失败 {}: {}", file_path.file_name().unwrap().to_string_lossy(), e);
}
}
} else {
uncategorized_count += 1;
}
}
println!("\n整理完成!");
println!(" 已分类: {} 个文件", categorized_count);
println!(" 未分类: {} 个文件", uncategorized_count);
Ok(undo_log)
}
/// 撤销整理
fn undo_organize() -> io::Result<()> {
let undo_log_path = get_undo_log_path();
if !undo_log_path.exists() {
println!("没有可撤销的操作记录");
return Ok(());
}
let mut undo_log = UndoLog::load(&undo_log_path)?;
if undo_log.is_empty() {
println!("没有可撤销的操作记录");
return Ok(());
}
let total = undo_log.records.len();
println!("\n开始撤销 {} 个文件移动...\n", total);
let mut success_count = 0;
let mut fail_count = 0;
// 从后往前撤销(最新的操作先撤销)
for record in undo_log.records.iter().rev() {
// 确保源目录存在
if let Some(parent) = record.source.parent() {
if !parent.exists() {
fs::create_dir_all(parent)?;
}
}
if record.destination.exists() {
match fs::rename(&record.destination, &record.source) {
Ok(_) => {
success_count += 1;
println!(" 已恢复: {}", record.source.file_name().unwrap().to_string_lossy());
}
Err(e) => {
fail_count += 1;
eprintln!(" 恢复失败 {}: {}",
record.source.file_name().unwrap().to_string_lossy(), e);
}
}
} else {
fail_count += 1;
eprintln!(" 文件不存在: {}", record.destination.display());
}
}
println!("\n撤销完成!");
println!(" 成功: {} 个文件", success_count);
println!(" 失败: {} 个文件", fail_count);
// 清空撤销日志
undo_log.clear();
undo_log.save(&undo_log_path)?;
Ok(())
}
/// 显示当前分类规则
fn show_rules(rules: &[CategoryRule]) {
println!("\n当前分类规则:");
println!("{}", "─".repeat(50));
for (i, rule) in rules.iter().enumerate() {
println!("{}. {} ({})", i + 1, rule.name, rule.folder_name);
println!(" 扩展名: {}", rule.extensions.join(", "));
println!();
}
}
/// 添加自定义分类规则
fn add_rule(rules: &mut Vec<CategoryRule>, name: String, folder_name: String, extensions: Vec<String>) -> io::Result<()> {
// 检查是否已存在同名规则
if rules.iter().any(|r| r.name == name) {
println!("已存在同名规则: {}", name);
return Ok(());
}
rules.push(CategoryRule {
name,
folder_name,
extensions,
});
save_rules(rules)?;
println!("规则添加成功!");
Ok(())
}
/// 删除分类规则
fn remove_rule(rules: &mut Vec<CategoryRule>, index: usize) -> io::Result<()> {
if index == 0 || index > rules.len() {
println!("无效的规则索引");
return Ok(());
}
let removed = rules.remove(index - 1);
save_rules(rules)?;
println!("已删除规则: {}", removed.name);
Ok(())
}
/// 显示主菜单
fn show_menu() {
println!("\n╔════════════════════════════════════════╗");
println!("║ Windows 桌面图标归类整理工具 ║");
println!("╠════════════════════════════════════════╣");
println!("║ 1. 一键整理桌面 ║");
println!("║ 2. 撤销上次整理 ║");
println!("║ 3. 查看分类规则 ║");
println!("║ 4. 添加自定义规则 ║");
println!("║ 5. 删除分类规则 ║");
println!("║ 6. 恢复默认规则 ║");
println!("║ 7. 查看桌面文件 ║");
println!("║ 0. 退出 ║");
println!("╚════════════════════════════════════════╝");
print!("\n请选择操作 [0-7]: ");
io::stdout().flush().unwrap();
}
/// 读取用户输入
fn read_input() -> String {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
input.trim().to_string()
}
/// 一键整理桌面
fn cmd_organize(rules: &[CategoryRule]) {
println!("\n正在扫描桌面...");
match organize_desktop(rules) {
Ok(undo_log) => {
if !undo_log.is_empty() {
// 保存撤销日志
let undo_log_path = get_undo_log_path();
if let Err(e) = undo_log.save(&undo_log_path) {
eprintln!("保存撤销日志失败: {}", e);
}
}
}
Err(e) => {
eprintln!("整理失败: {}", e);
}
}
}
/// 查看桌面文件
fn cmd_show_desktop_files() {
let desktop_path = get_desktop_path();
let files = scan_desktop_files(&desktop_path);
if files.is_empty() {
println!("\n桌面上没有文件");
return;
}
println!("\n桌面文件列表 (共 {} 个):", files.len());
println!("{}", "─".repeat(50));
for (i, file) in files.iter().enumerate() {
println!("{}. {}", i + 1, file.file_name().unwrap().to_string_lossy());
}
}
fn main() {
println!("Windows 桌面图标归类整理工具");
println!("版本: 0.1.0\n");
// 确保配置目录存在
let config_dir = get_config_dir();
if let Err(e) = fs::create_dir_all(&config_dir) {
eprintln!("创建配置目录失败: {}", e);
}
let mut rules = load_rules();
loop {
show_menu();
let choice = read_input();
match choice.as_str() {
"1" => {
cmd_organize(&rules);
}
"2" => {
if let Err(e) = undo_organize() {
eprintln!("撤销失败: {}", e);
}
}
"3" => {
show_rules(&rules);
}
"4" => {
println!("\n添加自定义分类规则");
println!("{}", "─".repeat(30));
print!("分类名称: ");
io::stdout().flush().unwrap();
let name = read_input();
print!("文件夹名称: ");
io::stdout().flush().unwrap();
let folder_name = read_input();
print!("文件扩展名 (用逗号分隔,如: jpg,png,gif): ");
io::stdout().flush().unwrap();
let ext_input = read_input();
let extensions: Vec<String> = ext_input
.split(',')
.map(|s| s.trim().to_lowercase())
.filter(|s| !s.is_empty())
.collect();
if name.is_empty() || folder_name.is_empty() || extensions.is_empty() {
println!("输入不能为空");
continue;
}
if let Err(e) = add_rule(&mut rules, name, folder_name, extensions) {
eprintln!("添加规则失败: {}", e);
}
}
"5" => {
show_rules(&rules);
print!("\n请输入要删除的规则序号: ");
io::stdout().flush().unwrap();
let index: usize = read_input().parse().unwrap_or(0);
if let Err(e) = remove_rule(&mut rules, index) {
eprintln!("删除规则失败: {}", e);
}
}
"6" => {
print!("\n确定要恢复默认规则吗? (y/n): ");
io::stdout().flush().unwrap();
let confirm = read_input();
if confirm.to_lowercase() == "y" {
rules = default_rules();
if let Err(e) = save_rules(&rules) {
eprintln!("保存默认规则失败: {}", e);
} else {
println!("已恢复默认规则");
}
}
}
"7" => {
cmd_show_desktop_files();
}
"0" => {
println!("\n感谢使用,再见!");
break;
}
_ => {
println!("\n无效的选择,请重新输入");
}
}
}
}
