Rust: Rust 标准库关键类型:时间、环境与进程

最后更新:2026-08-26

Rust 标准库(std)提供了操作系统交互的核心类型——时间测量、环境变量、进程管理、路径操作。掌握这些类型,你的 Rust 程序就能真正与系统对话。

如果 Rust 语言本身是"发动机",那标准库就是"方向盘、仪表盘和导航系统"。没有标准库,你的程序只能做纯计算(加减乘除、字符串拼接)。有了标准库,程序才能:知道现在几点、读取命令行的参数、执行外部命令、操作文件路径——变成一个真正的"应用程序"。


1. 你将学到


2. 定时备份脚本的故事

(1) 痛苦:手动备份的痛苦

Tom 是一名运维工程师,每天下班前要手动备份服务器上的重要数据。这个流程让他非常苦恼:

"如果能写一个 Rust 程序:自动获取当前时间、读取环境变量里的备份路径、执行压缩命令、记录处理耗时……一切就完美了。"

(2) Rust 标准库的方案

RUST
use std::time::{Instant, SystemTime, UNIX_EPOCH};
use std::env;
use std::process::Command;

fn main() {
    let start = Instant::now();
    println!("=== 定时备份脚本 ===");

    // 1. 获取当前系统时间
    let now = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs();
    println!("[时间] 当前 Unix 时间戳: {}s", now);

    // 2. 读取环境变量
    let backup_dir = env::var("BACKUP_DIR")
        .unwrap_or_else(|_| String::from("./backup"));
    let db_name = env::var("DB_NAME")
        .unwrap_or_else(|_| String::from("my_database"));
    println!("[配置] 备份目录: {}", backup_dir);
    println!("[配置] 数据库名: {}", db_name);

    // 3. 构造备份文件名
    let archive_name = format!("{}/backup_{}.tar.gz", backup_dir, now);

    // 4. 执行无害的外部命令(模拟备份)
    let output = Command::new("echo")
        .arg(format!("Simulating backup of {} to {}", db_name, archive_name))
        .output()
        .expect("命令执行失败");

    println!("[执行] 命令输出: {}", String::from_utf8_lossy(&output.stdout));

    // 5. 计算耗时
    let elapsed = start.elapsed();
    println!("[耗时] 操作用时: {:?}", elapsed);
    println!("=== 备份完成 ===");
}

这个不到 30 行的脚本展示了 Rust 标准库的核心能力:Instant 测量耗时、SystemTime 获取系统时间、env::var 读取环境变量、Command 执行外部命令。每一个类型都是从操作系统获取信息或控制系统的"窗口"。


3. 核心概念

(1) 标准库关键类型体系

100%
graph TB
    A[Rust 标准库关键类型] --> B[时间相关]
    A --> C[环境相关]
    A --> D[进程相关]
    A --> E[路径相关]

    B --> B1["Duration: 时间段"]
    B --> B2["Instant: 瞬时计时"]
    B --> B3["SystemTime: 系统时钟"]

    C --> C1["env::args(): 命令行参数"]
    C --> C2["env::var(): 环境变量"]
    C --> C3["env::set_var(): 设置变量"]

    D --> D1["Command::new"]
    D --> D2["status() / output()"]
    D --> D3["stdin / stdout / stderr"]

    E --> E1["Path: 不可变路径切片"]
    E --> E2["PathBuf: 可增长的路径"]
    E --> E3["join / parent / exists"]

(2) 关键类型对比

类型/函数 所属模块 用途 关键方法
Duration std::time 时间段(如 5 秒、100 毫秒) from_secs, from_millis, as_secs
Instant std::time 程序启动以来的单调计时 now, elapsed, duration_since
SystemTime std::time 系统时钟时间(可被 NTP 调整) now, duration_since, UNIX_EPOCH
env::args std::env 读取命令行参数 返回 Args 迭代器
env::var std::env 读取环境变量 返回 Result<String, VarError>
Command std::process 执行外部命令 new, arg, output, status
PathBuf std::path 可修改的文件路径 push, pop, set_extension
Path std::path 不可变的路径引用 exists, is_file, parent, join

(3) Path 与 PathBuf 的关系

Path PathBuf
类似字符串类型 &str(不可变引用) String(拥有所有权)
可变性 不可变(只读操作) 可变(push、pop 等)
内存位置 栈或堆上的引用 堆上的缓冲区
常用操作 exists, is_dir, parent, join push, pop, set_extension
转换 path.to_path_buf() → PathBuf path_buf.as_path() → &Path

(4) 时间类型对比速查

类型 用途 单调递增 精度 可被系统调整 典型用法
Instant 程序内计时 纳秒 测量代码耗时
SystemTime 系统时钟时间 纳秒 是(NTP 等) 获取当前日期时间
Duration 时间段/间隔 N/A 纳秒 N/A 超时、睡眠、加减运算

PathPathBuf 的关系完全类比 &strStringPathBuf 是拥有所有权的可变路径,Path 是借用的不可变路径切片。所有路径操作(joinparent 等)都在 Path 上定义。


4. 标准库关键类型示例

▶ 示例 1:时间测量——Duration、Instant 与 SystemTime(难度 ⭐)

RUST
// ============================================
// 演示:std::time 模块的三种时间类型
// 模拟:程序计时器和系统时钟
// ============================================

use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};

fn main() {
    println!("=== 时间类型演示 ===\n");

    // --- 1. Duration:时间段 ---
    let five_secs = Duration::from_secs(5);
    let hundred_ms = Duration::from_millis(100);
    let two_mins = Duration::from_secs(2 * 60);

    println!("[Duration] 5秒   = {:?}", five_secs);
    println!("[Duration] 100ms = {:?}", hundred_ms);
    println!("[Duration] 2分钟 = {:?}", two_mins);

    // Duration 运算:加减和比较
    let total = five_secs + hundred_ms;
    println!("[Duration] 5秒+100ms = {:?}", total);
    println!("[Duration] 5秒 > 100ms = {}", five_secs > hundred_ms);

    // --- 2. Instant:程序计时 ---
    let start = Instant::now();

    // 模拟一些耗时操作
    let mut sum: u64 = 0;
    for i in 0..1_000_000 {
        sum = sum.wrapping_add(i);
    }

    let elapsed = start.elapsed();
    println!("\n[Instant] 计算 sum={} 耗时: {:?}", sum, elapsed);
    println!("[Instant] 耗时毫秒: {}ms", elapsed.as_millis());
    println!("[Instant] 耗时微秒: {}µs", elapsed.as_micros());

    // --- 3. SystemTime:系统时间 ---
    let now = SystemTime::now();
    let since_epoch = now.duration_since(UNIX_EPOCH).unwrap();

    println!("\n[SystemTime] 当前时间戳: {} 秒", since_epoch.as_secs());
    println!("[SystemTime] 当前时间戳: {} 毫秒", since_epoch.as_millis());

    // 计算一天前的时间
    let one_day_ago = now - Duration::from_secs(24 * 60 * 60);
    let since_epoch_ago = one_day_ago.duration_since(UNIX_EPOCH).unwrap();
    println!("[SystemTime] 一天前的时间戳: {} 秒", since_epoch_ago.as_secs());

    println!("\n=== 时间演示结束 ===");
}

输出:

TEXT 📖 仅展示
=== 时间类型演示 ===

[Duration] 5秒   = 5s
[Duration] 100ms = 100ms
[Duration] 2分钟 = 120s
[Duration] 5秒+100ms = 5.1s
[Duration] 5秒 > 100ms = true

[Instant] 计算 sum=499999500000 耗时: 2.345ms
[Instant] 耗时毫秒: 2ms
[Instant] 耗时微秒: 2345µs

[SystemTime] 当前时间戳: 1783012250 秒
[SystemTime] 当前时间戳: 1783012250123 毫秒
[SystemTime] 一天前的时间戳: 1782925850 秒

=== 时间演示结束 ===

Duration 表示时间段(如 "5 秒"),支持加减和比较运算。Instant 是"程序启动以来的单调计时器"——适合测量代码执行时间,不受系统时间调整影响。SystemTime 读取系统时钟(可被 NTP 调整),适合获取当前日期时间。duration_since(UNIX_EPOCH) 获取 Unix 时间戳。


▶ 示例 2:环境与命令行参数——env::args 和 env::var(难度 ⭐⭐)

RUST
// ============================================
// 演示:std::env 模块读取命令行参数和环境变量
// 模拟:一个可配置的备份工具
// ============================================

use std::env;

fn main() {
    println!("=== 环境与参数探查器 ===\n");

    // --- 1. 读取命令行参数 ---
    let args: Vec<String> = env::args().collect();
    println!("[args] 命令行参数数量: {}", args.len());

    if args.len() > 1 {
        println!("[args] 程序名: {}", args[0]);
        println!("[args] 传入参数:");
        for (i, arg) in args.iter().enumerate().skip(1) {
            println!("  args[{}] = {}", i, arg);
        }
    } else {
        println!("[args] 没有传入额外参数");
        println!("[args] 提示: 运行方式如下");
        println!("  cargo run -- --mode=backup --target=./data");
    }

    // --- 2. 读取环境变量 ---
    println!("\n--- 环境变量探查 ---");

    // 尝试读取几个常见的环境变量
    check_env_var("PATH");
    check_env_var("HOME");
    check_env_var("USER");
    check_env_var("BACKUP_DIR");    // 可能不存在
    check_env_var("DB_CONNECTION"); // 可能不存在

    // --- 3. 读取并解析自定义配置 ---
    println!("\n--- 配置解析 ---");

    // 设置一个环境变量用于演示(仅在当前进程有效)
    // 注意:set_var 在实际项目中谨慎使用,会影响当前进程
    env::set_var("MY_APP_MODE", "backup");
    env::set_var("MY_APP_VERBOSE", "true");

    let mode = env::var("MY_APP_MODE").unwrap_or_else(|_| "default".to_string());
    let verbose = env::var("MY_APP_VERBOSE")
        .map(|v| v == "true" || v == "1")
        .unwrap_or(false);

    println!("[配置] 运行模式: {}", mode);
    println!("[配置] 详细输出: {}", verbose);

    // --- 4. 遍历所有环境变量(仅演示前几个)---
    println!("\n--- 环境变量列表(前5个)---");
    for (i, (key, value)) in env::vars().enumerate().take(5) {
        println!("  {} = {}", key, value);
    }

    println!("\n=== 探查结束 ===");
}

/// 尝试读取环境变量并打印
fn check_env_var(name: &str) {
    match env::var(name) {
        Ok(val) => println!("[env] {} = {}", name, val),
        Err(env::VarError::NotPresent) => println!("[env] {} = (未设置)", name),
        Err(env::VarError::NotUnicode(_)) => println!("[env] {} = (非 UTF-8 值)", name),
    }
}

输出:

TEXT 📖 仅展示
=== 环境与参数探查器 ===

[args] 命令行参数数量: 1
[args] 没有传入额外参数
[args] 提示: 运行方式如下
  cargo run -- --mode=backup --target=./data

--- 环境变量探查 ---
[env] PATH = C:\Windows\system32;C:\Windows;...
[env] HOME = (未设置)
[env] USER = (未设置)
[env] BACKUP_DIR = (未设置)
[env] DB_CONNECTION = (未设置)

--- 配置解析 ---
[配置] 运行模式: backup
[配置] 详细输出: true

--- 环境变量列表(前5个)---
  ALLUSERSPROFILE = C:\ProgramData
  APPDATA = C:\Users\Administrator\AppData\Roaming
  ...

=== 探查结束 ===

env::args() 返回命令行参数迭代器,第一个元素是程序路径。env::var(name) 读取环境变量,返回 Result<String, VarError>——可能因为变量不存在(NotPresent)或值不是有效 Unicode(NotUnicode)而失败。env::set_var 可以设置环境变量(仅当前进程有效)。env::vars() 遍历所有环境变量。


▶ 示例 3:Command 与 Path——执行外部命令和路径操作(难度 ⭐⭐)

RUST
// ============================================
// 演示:std::process::Command 与 std::path::Path/PathBuf
// 模拟:备份脚本——构建路径、执行压缩命令
// ============================================

use std::path::{Path, PathBuf};
use std::process::Command;

fn main() {
    println!("=== 路径操作与外部命令演示 ===\n");

    // --- 1. Path 和 PathBuf 基本操作 ---
    println!("--- 路径操作 ---");

    // 创建 PathBuf(拥有所有权的可变路径)
    let mut backup_dir = PathBuf::new();
    backup_dir.push("data");
    backup_dir.push("backups");
    println!("[PathBuf] 初始路径: {}", backup_dir.display());

    // 设置文件扩展名
    let mut archive = backup_dir.clone();
    archive.push("database");
    archive.set_extension("tar.gz");
    println!("[PathBuf] 归档文件: {}", archive.display());

    // Path 的只读操作
    let path = Path::new("C:/Users/Alice/Documents/report.pdf");
    println!("\n[Path] 文件路径: {}", path.display());
    println!("[Path] 文件名: {:?}", path.file_name());
    println!("[Path] 扩展名: {:?}", path.extension());
    println!("[Path] 父目录: {:?}", path.parent());
    println!("[Path] 是否存在: {}", path.exists());

    // 路径拼接
    let docs = Path::new("./docs");
    let full_path = docs.join("rust").join("guide.md");
    println!("[Path] 拼接路径: {}", full_path.display());

    // --- 2. 使用 Command 执行外部命令 ---
    println!("\n--- 外部命令执行 ---");

    // 示例 A:执行 "echo" 命令(无害命令)
    let echo_result = Command::new("echo")
        .arg("Hello from Rust! Backup process started.")
        .output()
        .expect("echo 命令执行失败");

    println!("[Command] echo 输出: {}",
        String::from_utf8_lossy(&echo_result.stdout));

    // 示例 B:执行 "whoami" 命令(显示当前用户)
    let whoami_output = Command::new("whoami")
        .output()
        .expect("whoami 命令执行失败");

    if whoami_output.status.success() {
        let username = String::from_utf8_lossy(&whoami_output.stdout);
        println!("[Command] 当前用户: {}", username.trim());
    } else {
        let err = String::from_utf8_lossy(&whoami_output.stderr);
        println!("[Command] whoami 失败: {}", err);
    }

    // 示例 C:检查命令是否成功(status 模式)
    let status = Command::new("cmd")
        .args(["/C", "dir", "./"])
        .status()
        .expect("dir 命令执行失败");

    if status.success() {
        println!("[Command] dir 命令执行成功 (exit code: {})", status.code().unwrap_or(-1));
    } else {
        println!("[Command] dir 命令执行失败 (exit code: {:?})", status.code());
    }

    // --- 3. 组合使用:根据路径构建命令 ---
    println!("\n--- 模拟备份流程 ---");

    let source = Path::new("./data/documents");
    let dest = Path::new("./backup/documents_backup.tar.gz");

    println!("备份源: {}", source.display());
    println!("备份目标: {}", dest.display());

    // 模拟 tar 命令(实际不会执行,只是展示命令构造方式)
    let _mock_cmd = Command::new("tar")
        .arg("-czf")
        .arg(dest)
        .arg(source)
        .status();

    // 实际执行一个无害的展示命令
    let show_cmd = Command::new("echo")
        .arg(format!(
            "Would execute: tar -czf {} {}",
            dest.display(),
            source.display()
        ))
        .output()
        .unwrap();

    println!("模拟命令: {}",
        String::from_utf8_lossy(&show_cmd.stdout).trim());

    println!("\n=== 演示结束 ===");
}

输出:

TEXT 📖 仅展示
=== 路径操作与外部命令演示 ===

--- 路径操作 ---
[PathBuf] 初始路径: data\backups
[PathBuf] 归档文件: data\backups\database.tar.gz

[Path] 文件路径: C:/Users/Alice/Documents/report.pdf
[Path] 文件名: Some("report.pdf")
[Path] 扩展名: Some("pdf")
[Path] 父目录: Some("C:/Users/Alice/Documents")
[Path] 是否存在: false
[Path] 拼接路径: docs\rust\guide.md

--- 外部命令执行 ---
[Command] echo 输出: Hello from Rust! Backup process started.

[Command] 当前用户: DESKTOP-ABC123\Administrator

[Command] dir 命令执行成功 (exit code: 0)

--- 模拟备份流程 ---
备份源: ./data/documents
备份目标: ./backup/documents_backup.tar.gz
模拟命令: Would execute: tar -czf ./backup/documents_backup.tar.gz ./data/documents

=== 演示结束 ===

Command::new("程序名") 创建一个新命令,通过 argargs 添加参数。output() 捕获 stdout 和 stderr(适合需要处理输出的场景),status() 只检查退出码(适合不需要输出的场景)。Path::display() 以跨平台方式显示路径。PathBufPath 的可变所有权版本,支持 pushpopset_extension 等修改操作。path.join(...) 返回一个新的 PathBuf


▶ 示例 4:综合练习——CLI 工具:文件信息查看器(难度 ⭐⭐⭐)

RUST
// ============================================
// 综合示例:std::fs + std::path + std::time
// ============================================

use std::env;
use std::fs;
use std::path::Path;
use std::time::SystemTime;

fn format_size(size: u64) -> String {
    const KB: u64 = 1024;
    const MB: u64 = 1024 * KB;
    const GB: u64 = 1024 * MB;
    if size >= GB { format!("{:.2} GB", size as f64 / GB as f64) }
    else if size >= MB { format!("{:.2} MB", size as f64 / MB as f64) }
    else if size >= KB { format!("{:.2} KB", size as f64 / KB as f64) }
    else { format!("{} B", size) }
}

fn format_time(systime: SystemTime) -> String {
    let duration = systime.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default();
    let secs = duration.as_secs();
    let days = secs / 86400;
    let hours = (secs % 86400) / 3600;
    let minutes = (secs % 3600) / 60;
    format!("{}天 {:02}:{:02} UTC", days, hours, minutes)
}

fn inspect_file(path_str: &str) -> Result<(), Box<dyn std::error::Error>> {
    let path = Path::new(path_str);
    if !path.exists() {
        println!("路径不存在: {}", path.display());
        return Ok(());
    }

    println!("=== 文件信息 ===");
    println!("路径: {}", path.display());
    println!("文件名: {:?}", path.file_name());
    println!("扩展名: {:?}", path.extension());
    println!("父目录: {:?}", path.parent());

    if path.is_file() {
        let metadata = fs::metadata(path)?;
        println!("大小: {}", format_size(metadata.len()));
        println!("只读: {}", metadata.permissions().readonly());
        println!("修改时间: {}", format_time(metadata.modified()?));
    } else if path.is_dir() {
        println!("类型: 目录");
        let entries: Vec<_> = fs::read_dir(path)?
            .filter_map(|e| e.ok())
            .collect();
        println!("条目数: {}", entries.len());
        for entry in entries.iter().take(10) {
            let name = entry.file_name().to_string_lossy().to_string();
            let tag = if entry.path().is_dir() { "DIR" } else { "FILE" };
            println!("  [{}] {}", tag, name);
        }
        if entries.len() > 10 {
            println!("  ... 还有 {} 个条目", entries.len() - 10);
        }
    }
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args: Vec<String> = env::args().collect();
    let target = if args.len() > 1 { &args[1] } else { "." };
    inspect_file(target)
}

输出(运行 cargo run -- src/main.rs):

TEXT 📖 仅展示
=== 文件信息 ===
路径: src/main.rs
文件名: Some("main.rs")
扩展名: Some("rs")
父目录: Some("src")
大小: 1.23 KB
只读: false
修改时间: 20504天 08:30 UTC

此示例综合运用了 std::fs(文件元数据)、std::path(路径操作)、std::time(时间格式化)和 std::env(命令行参数)。format_size 友好显示文件大小,format_timeSystemTime 转为可读时间。


▶ 示例 5:综合练习——简单计时器与系统信息(难度 ⭐⭐)

RUST
// ============================================
// 综合示例:std::time + std::env + std::process
// ============================================

use std::env;
use std::process::Command;
use std::time::{Duration, Instant};

struct Timer {
    start: Instant,
    label: String,
}

impl Timer {
    fn new(label: &str) -> Self {
        println!("[{}] 计时开始", label);
        Timer { start: Instant::now(), label: label.to_string() }
    }

    fn elapsed(&self) -> Duration {
        self.start.elapsed()
    }

    fn stop(self) -> Duration {
        let elapsed = self.elapsed();
        println!("[{}] 计时结束: {:.3}秒", self.label, elapsed.as_secs_f64());
        elapsed
    }
}

fn main() {
    println!("=== 系统信息 ===");
    println!("当前目录: {:?}", env::current_dir().unwrap_or_default());
    println!("操作系统: {}", env::consts::OS);
    println!("架构: {}", env::consts::ARCH);

    println!("\n=== 环境变量 ===");
    for key in &["HOME", "PATH", "USER", "LANG"] {
        match env::var(key) {
            Ok(val) => println!("{}: {} 字符", key, val.len()),
            Err(_) => println!("{}: (未设置)", key),
        }
    }

    println!("\n=== 计时演示 ===");
    let t1 = Timer::new("计算斐波那契");
    let mut fib: Vec<u64> = vec![0, 1];
    for _ in 0..45 {
        let next = fib[fib.len()-1] + fib[fib.len()-2];
        fib.push(next);
    }
    t1.stop();
    println!("fib(45) = {}", fib[45]);

    let t2 = Timer::new("字符串操作");
    let mut s = String::new();
    for i in 0..10_000 {
        s.push_str(&format!("item{} ", i));
    }
    let len = s.len();
    t2.stop();
    println!("字符串长度: {} 字符", len);

    println!("\n=== 进程退出码 ===");
    let status = Command::new("cmd")
        .args(&["/C", "echo", "hello"])
        .status();
    match status {
        Ok(s) => println!("退出码: {}", s.code().unwrap_or(-1)),
        Err(e) => println!("执行失败: {}", e),
    }
}

输出:

TEXT 📖 仅展示
=== 系统信息 ===
当前目录: "G:\\..."
操作系统: windows
架构: x86_64

=== 环境变量 ===
HOME: 20 字符
PATH: 500 字符
...

=== 计时演示 ===
[计算斐波那契] 计时开始
[计算斐波那契] 计时结束: X.XXX秒
fib(45) = 1134903170
[字符串操作] 计时开始
[字符串操作] 计时结束: X.XXX秒
字符串长度: 88889 字符

=== 进程退出码 ===
退出码: 0

Timer 利用 Instant 的 RAII 模式自动计时;env::consts 获取平台信息;env::var 读取环境变量;Command 执行外部命令并获取退出码。


❓ 常见问题

Q InstantSystemTime 有什么区别?什么时候用哪个?
A Instant 是单调递增的计时器,SystemTime 读取系统时钟。
Q env::varenv::args 返回的字符串编码是什么?
A 都是 UTF-8 编码的 String
Q Command::output()Command::status() 有什么区别?
A output() 捕获 stdout 和 stderr,status() 只检查退出码。
Q Path 和 PathBuf 在 Windows 和 Linux 上表现一样吗?
A PathPathBuf 是跨平台的,内部使用平台特定的路径分隔符。
QCommand 执行命令时,PATH 环境变量会被自动搜索吗?
A 是的,Command::new("程序名") 会搜索 PATH 环境变量。

📖 小节


📝 作业

  1. 难度 ⭐:写一个程序,使用 Instant 测量一个循环(1 到 1,000,000 累加)的执行时间,并分别以毫秒(ms)和微秒(µs)打印耗时。同时使用 SystemTime 获取程序启动时的 Unix 时间戳并打印。
  2. 难度 ⭐⭐:实现一个"环境变量查看器"。通过命令行参数传入一个环境变量名称,程序读取并打印其值。如果变量不存在,打印友好提示。额外功能:如果没有传入参数,列出所有以 MY_RUST_ 开头的环境变量及其值。
  3. 难度 ⭐⭐⭐:实现一个"简易备份工具"。使用 PathBuf 构建源目录和目标归档路径。通过环境变量 BACKUP_SOURCEBACKUP_DEST 读取配置(未设置则使用默认值 ./data./backup/archive.tar.gz)。使用 Command 执行 echo 命令模拟备份流程——打印"Backing up [source] to [dest]"。在开始和结束时使用 Instant 记录并打印总耗时。要求使用 Pathexists() 检查源目录是否存在。
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏