ohos-sdk配置Cargo 链接器,在鸿蒙PC上实现Rust三方库indicatif打造用于终端进度条、加载动画库
欢迎加入开源鸿蒙PC社区: https://harmonypc.csdn.net/
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
AtomGit 仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_rust_cargo
本文讲解鸿蒙 PC 端 Rust 开发环境搭建,鸿蒙基于 musl 库、强制二进制签名,无法直接使用通用 Linux 编译产物。需借助鸿蒙专属包管理器 Harmonybrew,提供两套编译方案:方案一安装 llvm-gcc-compat,零配置开箱即用;方案二仅安装 ohos-sdk,需手动配置 Cargo 链接器,二者都依托 ohos-sdk 完成自动签名编译。
完整的过程可以参考一下:
【OpenHarmony 鸿蒙 PC + CodeArts IDE 实现 Rust开发完整开发环境搭建指南】
一、indicatif 库介绍
indicatif 是 Rust 最流行的终端进度条、加载动画库,专门美化命令行输出,解决脚本/批量任务看不到执行进度的问题。
核心能力
- 基础进度条:显示当前/总量、百分比、速度、剩余时间
- 旋转加载动画(spinner):无固定总量的等待场景(文件下载、接口请求)
- 多进度条并行(同时多个任务进度)
- 自定义样式、彩色文字、自定义模板
- 支持长文本、换行日志不打乱进度条
适用场景
批量文件处理、数据库批量导入、文件下载、爬虫、打包编译、任何长时间运行的 CLI 工具。
二、安装命令
cargo add indicatif
自动写入 Cargo.toml:
[dependencies]
indicatif = "0.17"

三、完整无报错示例代码 main.rs
覆盖三大常用场景:旋转加载动画、单进度条、多并行进度条
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
use std::thread;
use std::time::Duration;
fn main() {
println!("===== 1. 旋转等待动画(无总量,等待场景) =====");
spinner_demo();
println!("\n===== 2. 标准带总量进度条 =====");
progress_bar_demo();
println!("\n===== 3. 多任务并行进度条 =====");
multi_progress_demo();
}
/// 旋转加载动画:不知道总数量时使用
fn spinner_demo() {
let sp = ProgressBar::new_spinner();
// template 返回 Result,必须 unwrap()
let style = ProgressStyle::default_spinner()
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ")
.template("{spinner:.blue} {msg}")
.unwrap();
sp.set_style(style);
sp.set_message("正在请求接口,请稍候...");
// 持续刷新动画
for _ in 0..30 {
sp.tick();
thread::sleep(Duration::from_millis(80));
}
sp.finish_with_message("✅ 接口请求完成");
}
/// 普通进度条:已知任务总量
fn progress_bar_demo() {
let total = 100;
let pb = ProgressBar::new(total);
// 进度模板解包
let style = ProgressStyle::default_bar()
.template(
"{msg}\n[{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({percent}%) 剩余:{eta}",
)
.unwrap()
.progress_chars("#>-");
pb.set_style(style);
pb.set_message("批量处理文件中");
for i in 0..total {
pb.set_position(i as u64);
thread::sleep(Duration::from_millis(30));
}
pb.finish_with_message("✅ 全部文件处理完毕");
}
/// 多任务并行进度条(同时显示多个进度)
fn multi_progress_demo() {
let multi = MultiProgress::new();
// 任务1 样式
let style1 = ProgressStyle::default_bar()
.template("[{bar:30.green}] {pos}/{len} {msg}")
.unwrap();
let pb1 = multi.add(ProgressBar::new(50));
pb1.set_message("任务一:图片压缩");
pb1.set_style(style1);
// 任务2 样式
let style2 = ProgressStyle::default_bar()
.template("[{bar:30.yellow}] {pos}/{len} {msg}")
.unwrap();
let pb2 = multi.add(ProgressBar::new(80));
pb2.set_message("任务二:数据入库");
pb2.set_style(style2);
// 两个线程模拟并行执行
let h1 = thread::spawn(move || {
for i in 0..50 {
pb1.set_position(i);
thread::sleep(Duration::from_millis(50));
}
pb1.finish_with_message("任务一完成");
});
let h2 = thread::spawn(move || {
for i in 0..80 {
pb2.set_position(i);
thread::sleep(Duration::from_millis(35));
}
pb2.finish_with_message("任务二完成");
});
// 等待线程结束
h1.join().unwrap();
h2.join().unwrap();
}

一、库基础前置说明
indicatif 是 Rust 命令行进度美化库,用于 CLI 工具展示加载旋转动画、单进度条、多并行进度条,解决长时间任务看不到执行状态的问题。
当前代码适配 indicatif 0.18+,.template() 返回 Result,必须调用 .unwrap() 解包,这是新版和旧版最大区别。
二、顶部导入解析
use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
use std::thread;
use std::time::Duration;
ProgressBar:核心进度对象,包含旋转加载器、固定总量进度条两种形态ProgressStyle:进度条样式构造器,自定义模板、颜色、填充字符、旋转图标MultiProgress:多进度条容器,支持终端同时展示多条独立进度(多线程并行任务)std::thread:多线程模拟并行任务std::time::Duration:线程休眠,模拟任务耗时
三、入口 main 函数
fn main() {
println!("===== 1. 旋转等待动画(无总量,等待场景) =====");
spinner_demo();
println!("\n===== 2. 标准带总量进度条 =====");
progress_bar_demo();
println!("\n===== 3. 多任务并行进度条 =====");
multi_progress_demo();
}
按顺序执行三类最常用进度组件,分开演示方便观察每种效果:
- 无总量旋转加载(不知道任务总数,如网络请求、文件读取)
- 已知总量进度条(批量文件、导入数据、下载文件)
- 多任务并行多条进度(同时跑多个独立任务)
四、函数1:spinner_demo 旋转加载动画
fn spinner_demo() {
let sp = ProgressBar::new_spinner();
// template 返回 Result,必须 unwrap()
let style = ProgressStyle::default_spinner()
.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ")
.template("{spinner:.blue} {msg}")
.unwrap();
sp.set_style(style);
sp.set_message("正在请求接口,请稍候...");
// 持续刷新动画
for _ in 0..30 {
sp.tick();
thread::sleep(Duration::from_millis(80));
}
sp.finish_with_message("✅ 接口请求完成");
}
分步拆解
ProgressBar::new_spinner()
创建无总量旋转加载器,适用于无法预知任务总数的等待场景:接口请求、读取大文件、等待第三方服务。ProgressStyle::default_spinner()
加载旋转动画默认样式基底.tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "):自定义旋转图标字符,循环切换形成转动效果.template("{spinner:.blue} {msg}"):定义输出模板{spinner:.blue}:旋转图标,蓝色字体{msg}:自定义提示文本占位
.unwrap():新版 template 返回 Result,解析模板无错误才取出样式对象,否则直接崩溃提示模板语法错误
sp.set_style(style):将自定义样式绑定到加载器sp.set_message("xxx"):填充模板里{msg}的文字- 循环
sp.tick():刷新旋转图标,配合休眠制造动画效果 sp.finish_with_message("✅ 接口请求完成"):任务结束,替换旋转动画为完成提示文字
适用场景
网络请求、数据库连接、未知大小文件读取、后台异步等待操作
五、函数2:progress_bar_demo 固定总量进度条
fn progress_bar_demo() {
let total = 100;
let pb = ProgressBar::new(total);
// 进度模板解包
let style = ProgressStyle::default_bar()
.template(
"{msg}\n[{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({percent}%) 剩余:{eta}",
)
.unwrap()
.progress_chars("#>-");
pb.set_style(style);
pb.set_message("批量处理文件中");
for i in 0..total {
pb.set_position(i as u64);
thread::sleep(Duration::from_millis(30));
}
pb.finish_with_message("✅ 全部文件处理完毕");
}
分步拆解
ProgressBar::new(total)
创建带固定总量的进度条,参数total为 u64 类型总任务数(此处100)ProgressStyle::default_bar()标准进度条样式基底
模板占位符解释:
| 占位符 | 作用 |
|--------|------|
|{msg}| 顶部自定义提示文字 |
|{elapsed_precise}| 已运行精确时间 |
|{bar:40.cyan/blue}| 进度条宽40字符,已完成青色、未完成蓝色 |
|{pos}/{len}| 当前进度 / 总任务 |
|{percent}| 完成百分比 |
|{eta}| 预估剩余时间 |
.progress_chars("#>-"):自定义进度条填充、分隔、空白字符.unwrap()解析模板
pb.set_position(i as u64):更新当前进度数值,自动刷新百分比、剩余时间- 循环休眠模拟每个任务耗时
finish_with_message:全部任务完成,输出完成标识
适用场景
批量文件转换、数据批量入库、文件下载、爬虫固定条数抓取
六、函数3:multi_progress_demo 多并行进度条
fn multi_progress_demo() {
let multi = MultiProgress::new();
// 任务1 样式
let style1 = ProgressStyle::default_bar()
.template("[{bar:30.green}] {pos}/{len} {msg}")
.unwrap();
let pb1 = multi.add(ProgressBar::new(50));
pb1.set_message("任务一:图片压缩");
pb1.set_style(style1);
// 任务2 样式
let style2 = ProgressStyle::default_bar()
.template("[{bar:30.yellow}] {pos}/{len} {msg}")
.unwrap();
let pb2 = multi.add(ProgressBar::new(80));
pb2.set_message("任务二:数据入库");
pb2.set_style(style2);
// 两个线程模拟并行执行
let h1 = thread::spawn(move || {
for i in 0..50 {
pb1.set_position(i);
thread::sleep(Duration::from_millis(50));
}
pb1.finish_with_message("任务一完成");
});
let h2 = thread::spawn(move || {
for i in 0..80 {
pb2.set_position(i);
thread::sleep(Duration::from_millis(35));
}
pb2.finish_with_message("任务二完成");
});
// 等待线程结束
h1.join().unwrap();
h2.join().unwrap();
}
分步拆解
MultiProgress::new()
多进度条管理器,解决多条进度条输出互相覆盖、排版混乱问题,自动分行管理多个 ProgressBarmulti.add(ProgressBar)
把单个进度条加入管理器,所有进度条共用终端输出流,互不干扰- 分别构建两个独立进度条,设置不同颜色(绿色/黄色)、不同总任务量、不同提示文字
thread::spawn(move || {})
创建独立线程分别更新两条进度,模拟并行执行两个业务任务move闭包捕获进度条所有权移入线程- 循环内不断更新进度位置,休眠模拟业务处理耗时
h1.join().unwrap(); h2.join().unwrap();
主线程阻塞等待两个子线程全部执行完毕,防止程序提前退出进度条消失
适用场景
多文件同时下载、多目录并行处理、多数据源同步导入、多爬虫任务并发执行
七、核心使用总结
- 不知道任务总数 →
ProgressBar::new_spinner()旋转加载器 - 固定任务总量单任务 →
ProgressBar::new(num)标准进度条 - 多并发任务同时展示多条进度 → 搭配
MultiProgress容器 - 0.18+ 版本模板字符串后必须加
.unwrap()解包 Result - 所有进度更新、完成、提示文字 API 统一,上手成本极低
四、核心API详细解释
1. ProgressBar 两种创建方式
-
旋转动画:
ProgressBar::new_spinner()
适合无明确总量:网络请求、等待资源、后台加载.tick():刷新旋转图标.set_message("文字"):左侧提示文字.finish_with_message("完成提示"):结束后替换文字
-
固定总量进度条:
ProgressBar::new(总数值u64).set_position(当前数值)更新进度.inc(1)自增1(简写写法).finish()/.finish_with_message()标记完成
2. ProgressStyle 模板占位符(常用)
| 占位符 | 含义 |
|---|---|
{spinner} |
旋转图标 |
{bar:宽度.前景/背景} |
进度条主体 |
{pos} |
当前进度 |
{len} |
总长度 |
{percent} |
百分比 |
{elapsed_precise} |
已运行时间 |
{eta} |
预估剩余时间 |
{msg} |
自定义提示文本 |
3. MultiProgress 多进度条
MultiProgress::new()创建进度条容器multi.add(pb)将进度条加入容器,实现多行同时展示- 搭配多线程可模拟并行任务进度
五、极简常用片段(直接复制使用)
简易自增进度条
use indicatif::ProgressBar;
use std::time::Duration;
fn simple_bar() {
let pb = ProgressBar::new(20);
for _ in 0..20 {
pb.inc(1);
std::thread::sleep(Duration::from_millis(100));
}
pb.finish();
}
简易加载spinner
use indicatif::ProgressBar;
use std::time::Duration;
fn simple_spin() {
let sp = ProgressBar::new_spinner();
sp.set_message("加载中...");
for _ in 0..20 {
sp.tick();
std::thread::sleep(Duration::from_millis(100));
}
sp.finish();
}
六、典型业务场景
- 爬虫批量请求页面,展示爬取进度
- 本地批量转换图片/视频,可视化处理进度
- 命令行文件上传/下载进度展示
- 大数据批量导入数据库,直观查看剩余任务量
- CLI工具长时间任务优化终端交互体验
更多推荐



所有评论(0)