Rust简要汇总(持续更新)
<p>Rust工具: https://www.rust-lang.org/tools/install</p><h1 id="1-cargo">1 cargo</h1>
<pre><code class="language-rust">cargo new my_test
</code></pre>
<p>开始于单元包的根节点:在编译一个单元包时,编译器会从单元包的根节点文件开始编译(通常是库单元包中的src/lib.rs,或二进制单元包中的src/main.rs)。</p>
<h1 id="2-thread">2 thread</h1>
<p>在 Rust 中,<code>handle.join().unwrap()</code> 是用于等待线程完成并获取其返回值的常见操作。<br>
<code>join()</code> 方法返回一个 <code>Result<T, Box<dyn Error>></code>,其中 <code>T</code> 是被等待线程的返回值类型。使用 <code>unwrap()</code> 是一种简单的错误处理方式,它会:</p>
<ul>
<li>如果结果是 <code>Ok(t)</code>,则返回内部的值 <code>t</code></li>
<li>如果结果是 <code>Err(e)</code>,则会触发 panic 并显示错误信息</li>
</ul>
<pre><code class="language-rust">fn main() {
// 创建一个线程并获取其句柄
let handle = thread::spawn(|| {
thread::sleep(Duration::from_secs(1));
"线程执行完成" // 线程的返回值
});
// 等待线程完成并获取返回值
let result = handle.join().unwrap();
println!("{}", result); // 输出: 线程执行完成
}
</code></pre>
<p>在 Rust 中,<code>let _ = handle.join();</code> 是一种处理线程 JoinHandle 的方式,它的作用是:</p>
<ol>
<li>调用 <code>join()</code> 方法阻塞当前线程,等待被 spawn 的线程执行完成</li>
<li>使用 <code>let _ =</code> 忽略 <code>join()</code> 返回的 Result 值<br>
与 <code>handle.join().unwrap()</code> 不同,这种写法会静默忽略任何可能的错误,包括线程恐慌。</li>
</ol>
<h1 id="3-安装">3 安装</h1>
<pre><code class="language-bash">curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
</code></pre>
<p>或者</p>
<pre><code class="language-bash">wget --https-only --secure-protocol=TLSv1_2 -qO- https://sh.rustup.rs | sh
</code></pre>
<p>刷新环境变量<br>
安装完成后,需要让终端识别新安装的 <code>rustup</code> 命令,执行:</p>
<pre><code class="language-bash">source $HOME/.cargo/env
</code></pre>
<h2 id="31-问题">3.1 问题</h2>
<ol>
<li>安装rustup时报错:</li>
</ol>
<pre><code class="language-bash"> root@ceph-221:/home/code/eza# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
info: downloading installer
warn: It looks like you have an existing installation of Rust at:
warn: /usr/bin
warn: It is recommended that rustup be the primary Rust installation.
warn: Otherwise you may have confusion unless you are careful with your PATH.
warn: If you are sure that you want both rustup and your already installed Rust
warn: then please reply `y' or `yes' or set RUSTUP_INIT_SKIP_PATH_CHECK to yes
warn: or pass `-y' to ignore all ignorable checks.
error: cannot install while Rust is installed
</code></pre>
<p>解决方法:<br>
这个错误是因为系统中已经通过包管理器(如 <code>apt</code>、<code>yum</code> 等)安装了 Rust,而 <code>rustup</code> 检测到了现有安装,为了避免环境冲突而终止了安装。解决方法如下:<br>
为了让 <code>rustup</code> 成为主要的 Rust 工具链管理器,建议先卸载系统预装的 Rust:</p>
<pre><code class="language-bash">sudo dnf remove rust cargo
</code></pre>
<p>卸载完成后,重新运行 <code>rustup</code> 安装脚本。</p>
<h1 id="4-格式化输出">4 格式化输出</h1>
<p>在 Rust 中,<code>println!("{:?}", other);</code> 是一个用于打印变量 <code>other</code> 调试信息的宏调用,其中 <code>{:?}</code> 是格式化占位符,对应 <strong><code>Debug</code> 格式化输出</strong>。</p>
<h3 id="411-核心作用">4.1.1 核心作用</h3>
<ul>
<li><code>{:?}</code> 要求被打印的类型实现了标准库的 <code>std::fmt::Debug</code> trait,该 trait 用于提供类型的调试友好格式(通常包含详细的内部结构)。</li>
<li>与 <code>{}</code>(对应 <code>Display</code> trait)不同,<code>Debug</code> 输出更偏向开发者调试,格式可能更冗长(例如包含字段名、引号等),且通常由编译器自动派生(通过 <code>#</code>),无需手动实现。</li>
<li><code>{:?}</code> 的变体 <code>{:#?}</code> 会生成<strong>带缩进的多行格式</strong>,适合复杂结构(如嵌套的结构体、长列表):</li>
</ul>
<h1 id="5-所有权">5 所有权</h1>
<p>在Rust中,由Copy trait来区分值语义和引用语义。与此同时,Rust也引入了新的语义:复制(Copy)语义和移动(Move)语义。复制语义对应值语义,移动语义对应引用语义。</p>
<p>Rust的借用检查器(borrow checker),借用检查器会检查所有数据访问是否合法。借用检查依赖于3个紧密关联的概念:所有权、生命周期和借用。</p>
<ul>
<li>所有权(ownership)是一个引申而来的比喻,在Rust中,所有权与针对不再需要的值的清理有关。</li>
<li>值的生命周期是一个时间段,在此时间段内对该值的访问是有效的行为。</li>
<li>借用一个值意味着要访问它。</li>
</ul>
<p>所有权的特点:</p>
<ol>
<li>控制资源(不仅仅是内存)的释放</li>
<li>出借所有权,包括不可变(共享)和可变(独占)的
<ol>
<li>通过使用&操作完成所有权租借</li>
<li>在不可变借用期间,所有者不能修改资源,也不能在进行可变借用</li>
<li>在可变借用期间,所有者不能访问资源,并且也不能再出借所有权</li>
<li>不可变借用可以出借多次,因为他不能修改内存数据;可变借用只能出借一次,否则难以预料数据何时何地被修改。</li>
</ol>
</li>
<li>转移所有权</li>
</ol>
<p>生命周期参数的目的是帮助借用检查器验证合法的引用,消除悬垂指针</p>
<ul>
<li>借用的生命周期不能长于出借方的生命周期</li>
<li>结构体实例的生命周期应短于或等于任意一个成员的生命周期</li>
</ul>
<p>省略生命周期参数</p>
<ol>
<li>每个输入位置上省略的生命周期都将成为一个不同的生命周期参数</li>
<li>如果只有一个输入生命周期的位置(不管是否忽略),则该生命周期都将分配给输出生命周期</li>
<li>如果存在多个输入生命周期的位置,但是其中包含着&self或&mut self,则self的生命周期都将分配给输出生命周期</li>
</ol>
<p>对于Box<T>类型来说,如果包含的类型T属于复制语义,则执行按位复制;如果属于移动语义,则移动所有权</p>
<h1 id="6-类型">6 类型</h1>
<h2 id="61-sized">6.1 ?Sized</h2>
<p>在 Rust 中,<code>?Sized</code> 是一个用于 trait bound 的特殊标记,用于表示“允许类型不实现 <code>Sized</code> trait”。要理解它,首先需要了解 <code>Sized</code> trait 本身:</p>
<h3 id="611-sized-trait-是什么">6.1.1 Sized trait 是什么?</h3>
<p><code>Sized</code> 是 Rust 中的一个<strong>自动实现的 trait</strong>,用于标记“在编译时已知大小的类型”(例如 <code>i32</code>、<code>String</code>、自定义结构体等)。</p>
<ul>
<li>对于这类类型,编译器知道它们在内存中占据的精确大小,因此可以直接在栈上分配,也能作为函数参数/返回值直接传递。</li>
<li>反之,<strong>动态大小类型(DST,Dynamically Sized Type)</strong> 则不实现 <code>Sized</code>,例如:
<ul>
<li>切片 <code></code>(长度未知,需通过 <code>&</code> 等指针间接使用);</li>
<li>trait 对象(如 <code>dyn Trait</code>,具体类型大小未知);</li>
<li>字符串字面量的底层类型 <code>str</code>(长度未知,需通过 <code>&str</code> 使用)。</li>
</ul>
</li>
</ul>
<p><strong><code>?Sized</code> 的作用:放宽 <code>Sized</code> 限制</strong><br>
Rust 中,<strong>泛型默认隐含 <code>Sized</code> 约束</strong>。例如:</p>
<pre><code class="language-rust">fn foo<T>(x: T) { ... }
// 等价于
fn foo<T: Sized>(x: T) { ... }
</code></pre>
<p>这意味着泛型 <code>T</code> 只能接受编译时大小已知的类型(<code>Sized</code> 类型)。</p>
<p>而 <code>?Sized</code> 的作用是<strong>取消这种默认约束</strong>,允许泛型接受“可能不实现 <code>Sized</code> 的类型”。例如:</p>
<pre><code class="language-rust">fn bar<T: ?Sized>(x: &T) { ... }
</code></pre>
<p>这里 <code>T</code> 可以是 <code>Sized</code> 类型(如 <code>i32</code>),也可以是动态大小类型(如 <code>str</code>、<code>dyn Trait</code>)。</p>
<h3 id="612-使用场景">6.1.2 使用场景</h3>
<p><code>?Sized</code> 通常用于需要处理动态大小类型的场景,常见情况:</p>
<ul>
<li>
<p><strong>接受 trait 对象</strong>:<br>
trait 对象(<code>dyn Trait</code>)是 DST,因此泛型需要 <code>?Sized</code> 才能接受它:</p>
<pre><code class="language-rust">trait MyTrait { fn do_something(&self); }
// 允许 T 为 dyn MyTrait(DST)
fn call_trait<T: MyTrait + ?Sized>(x: &T) {
x.do_something();
}
// 使用:可以传入任何实现 MyTrait 的类型的引用,或 trait 对象
let obj: &dyn MyTrait = &SomeType;
call_trait(obj); // 合法
</code></pre>
</li>
<li>
<p><strong>处理切片或字符串</strong>:<br>
直接使用 <code></code> 或 <code>str</code> 时(通常通过引用):</p>
<pre><code class="language-rust">// 接受 str(DST)的引用
fn print_str<T: ?Sized>(s: &T) where T: AsRef<str> {
println!("{}", s.as_ref());
}
print_str("hello"); // 字符串字面量是 &str,底层是 str(DST)
</code></pre>
</li>
<li>
<p><strong>定义容纳 DST 的类型</strong>:<br>
例如自定义智能指针时,指向 DST:</p>
<pre><code class="language-rust">struct MyBox<T: ?Sized>(*const T);
impl<T: ?Sized> MyBox<T> {
fn new(x: &T) -> Self {
MyBox(x as *const T)
}
}
</code></pre>
</li>
</ul>
<h3 id="613-注意点">6.1.3 注意点</h3>
<ul>
<li><code>?Sized</code> 仅用于泛型约束,不能直接修饰具体类型。</li>
<li>由于 DST 无法在栈上直接存储或作为值传递,使用 <code>?Sized</code> 的泛型通常需要通过<strong>引用(<code>&T</code>)</strong> 或<strong>指针(如 <code>Box<T></code>、<code>Rc<T></code>)</strong> 间接操作。</li>
<li><code>?Sized</code> 是“允许不 <code>Sized</code>”,而非“必须不 <code>Sized</code>”,因此仍能接受 <code>Sized</code> 类型。</li>
</ul>
<h1 id="7-log">7 log</h1>
<p><code>RUST_LOG</code> 是 Rust 生态中用于控制 <strong>日志输出</strong> 的环境变量,主要配合 Rust 的日志库(如 <code>log</code>、<code>tracing</code>)使用,用于动态调整日志的 <strong>级别</strong>、<strong>模块范围</strong> 和 <strong>输出内容</strong>,无需修改代码即可灵活控制程序的日志行为。<br>
log是Rust 生态中最基础、应用最广泛的 <strong>日志抽象库</strong>(crate),它本身不直接实现日志的输出功能,而是定义了一套统一的日志接口(如日志级别、宏定义),让其他库或应用可以基于这套接口实现日志记录,同时保证不同日志实现之间的兼容性</p>
<ol>
<li><strong>提供统一的日志接口</strong>:<br>
定义了 <code>trace!</code>、<code>debug!</code>、<code>info!</code>、<code>warn!</code>、<code>error!</code> 等日志宏,以及 <code>Log</code>、<code>Level</code>、<code>Metadata</code> 等核心 trait 和枚举,让开发者可以用一致的方式编写日志代码,无需关心底层如何输出(如打印到终端、写入文件、发送到日志服务器等)。</li>
<li><strong>解耦日志生产与消费</strong>:<br>
库开发者只需依赖 <code>log</code> 库编写日志(如 <code>info!("初始化完成")</code>),而应用开发者可以自由选择日志的实现方式(如 <code>env_logger</code>、<code>tracing</code>、<code>fern</code> 等),两者通过 <code>log</code> 的接口对接,避免了库与特定日志实现的强耦合。</li>
<li>常用搭配的日志实现库<br>
<code>log</code> 库本身不输出日志,必须配合具体的 “日志实现库” 才能生效,常见的有:
<ul>
<li><strong><code>env_logger</code></strong>:通过 <code>RUST_LOG</code> 环境变量控制日志输出,适合命令行工具和开发调试。</li>
<li><strong><code>tracing</code></strong>:更强大的日志和追踪库,支持结构化日志、跨度(span)追踪,适合复杂应用和分布式系统。</li>
<li><strong><code>fern</code></strong>:支持将日志输出到文件、终端等多种目标,可自定义格式和滚动策略。</li>
<li><strong><code>simple_logger</code></strong>:简单轻量的实现,适合快速上手,无需复杂配置。</li>
</ul>
</li>
</ol>
<h2 id="71-日志级别从低到高">7.1 日志级别(从低到高)</h2>
<p>Rust 日志库定义了 5 个标准级别(级别越高,输出日志越少):</p>
<ul>
<li><code>trace</code>:最详细的调试信息(如函数调用参数、循环步骤),通常用于开发阶段细粒度调试。</li>
<li><code>debug</code>:调试信息(如关键流程节点、变量值),适合开发和测试环境。</li>
<li><code>info</code>:普通运行信息(如程序启动、任务完成),生产环境常用。</li>
<li><code>warn</code>:警告信息(如不影响运行的异常情况,如“配置项缺失,使用默认值”)。</li>
<li><code>error</code>:错误信息(如功能失败、资源不可用),必须关注的问题。</li>
</ul>
<p><strong>规则</strong>:设置某一级别后,会输出该级别及所有更高级别的日志。例如,<code>RUST_LOG=info</code> 会输出 <code>info</code>、<code>warn</code>、<code>error</code> 级别的日志。</p>
<h2 id="72-基本设置方法">7.2 基本设置方法</h2>
<h3 id="721-全局设置日志级别">7.2.1 全局设置日志级别</h3>
<p>通过 <code>RUST_LOG=<级别></code> 控制全局日志输出:</p>
<pre><code class="language-bash"># 只输出 error 及以上级别日志(最简洁)
RUST_LOG=error cargo run
# 输出 info 及以上级别(info, warn, error)
RUST_LOG=info ./my_rust_program
# 输出 debug 及以上级别(开发调试常用)
RUST_LOG=debug cargo test
# 输出所有级别(包括 trace,最详细)
RUST_LOG=trace ./my_rust_program
</code></pre>
<h3 id="722-限定模块-crate-的日志范围">7.2.2 限定模块/ crate 的日志范围</h3>
<p>通过 <code>RUST_LOG=<模块路径>=<级别></code> 只输出特定模块的日志,避免全局日志冗余:</p>
<pre><code class="language-bash"># 只输出 my_project 中 network 模块的 debug 级别日志
RUST_LOG=my_project::network=debug cargo run
# 输出 tokio 库的 info 日志 + 自己代码的 debug 日志
RUST_LOG=tokio=info,my_project=debug ./my_program
# 禁用某个模块的日志(设置为 off)
RUST_LOG=my_project::legacy=off ./my_program
</code></pre>
<ul>
<li>模块路径对应代码中的 <code>mod</code> 结构(如 <code>crate::utils::file</code>)。</li>
<li>可以指定第三方 crate 的名称(如 <code>tokio</code>、<code>hyper</code>),控制其日志输出。</li>
</ul>
<h3 id="723-组合设置多模块--不同级别">7.2.3 组合设置(多模块 + 不同级别)</h3>
<p>用逗号分隔多个规则,实现精细化控制:</p>
<pre><code class="language-bash"># 全局 info 级别,但 network 模块用 debug,tokio 库用 warn
RUST_LOG=info,my_project::network=debug,tokio=warn ./my_program
</code></pre>
<h3 id="724-在代码中读取-rust_log">7.2.4 在代码中读取 <code>RUST_LOG</code></h3>
<p>需配合日志库(如 <code>log</code> + <code>env_logger</code>)在程序中初始化日志系统,才能让 <code>RUST_LOG</code> 生效。示例:</p>
<ol>
<li>
<p>在 <code>Cargo.toml</code> 中添加依赖:</p>
<pre><code class="language-toml">
log = "0.4" # 日志基础库
env_logger = "0.9" # 解析 RUST_LOG 的库
</code></pre>
</li>
<li>
<p>在代码中初始化:</p>
<pre><code class="language-rust">use log::{info, debug, error};
fn main() {
// 初始化日志系统,读取 RUST_LOG 环境变量
env_logger::init();
info!("程序启动");
debug!("配置文件路径: ./config.toml");// 仅 RUST_LOG>=debug 时输出
error!("数据库连接失败");
}
</code></pre>
</li>
</ol><br><br>
来源:https://www.cnblogs.com/lnp-v5/p/19568151
頁:
[1]