点击上方蓝字 江湖评谈设为关注/星标
前言
Rust有各种各样的花活儿,奇妙的操作。官方搞这些东西当然不是搞着玩的,主要是为了更契合Rust主打内存安全这一特性,也即是说为了万无一失的确保内存安全,才整出的这些奇妙的操作。主要是分为编译器魔法特性,DSL自定义,Unsafe不安全内存,极简线程池,生命周期等等,本篇分别看下。
奇妙操作之旅
一.编译器魔法特性
超级强大的编译器魔法特性,将为你展示零开销操作,生命周期绑定,泛型类型确定,自定义关联等四大特征。
先上代码(一套代码浓缩了以上四大特征):
use std::mem;
use std::marker::PhantomData;
struct MyType<T> {
_marker: PhantomData<T>,
}
struct MyLifetime<'a, T> {
_marker: PhantomData<&'a T>,
}
struct MyContainer<T> {
_marker: PhantomData<T>,
}
MyType<T> {
fn new() -> Self {
MyType { _marker: PhantomData }
}
}
fn main() {
//零开销
of MyType<u32>: {}", mem::size_of::<MyType<u32>>());
of PhantomData<u32>: {}", mem::size_of::<PhantomData<u32>>());
//生命周期绑定
let value = 42;
let _instance = MyLifetime::<i32> { _marker: PhantomData };
//泛型类型确认
let _instance2: MyContainer<u32> = MyContainer { _marker: PhantomData };
//自定义关联
let _instance3: MyType<String> = MyType::new();
}
以上代码完整的展示了零开销,生命周期绑定,泛型类型确定,自定义关联四大特征。下面一一解析下:
1.零开销
PhantomData<T> 是 Rust 标准库中提供的一个零大小类型(Zero-Sized Type, ZST),它的主要作用是告诉编译器你的结构体实际上与泛型参数 T 有关联,即使这个泛型参数没有被实际存储或使用。
确认这个零开销,我们直接使用以下代码打印出了其结构体大小,结果为0,完全没有任何代码。
println!("Size of MyType<u32>: {}", mem::size_of::<MyType<u32 ());
println!("Size of PhantomData<u32>: {}", mem::size_of::<PhantomData<u32>>());
结果:
Size of MyType<u32>: 0
Size of PhantomData<u32>: 0
2.生命周期默认绑定
_instance变量对i32的类型,引用了'a的生命周期。由于没有显式为 'a 指定生命周期来源,编译器会尽量推导出合理的结果:它发现 MyLifetime 的生命周期 'a 没有被直接约束到任何数据。然而,_marker 是 PhantomData<&'a T>,意味着它可以与某个实际数据(如 value)的生命周期相关联。因此,_instance 的生命周期会默认绑定到 value。
let value = 42;
let _instance = MyLifetime::<i32> { _marker: PhantomData };
3.泛型类型确定
_instance2通过 PhantomData 为泛型类型参数 T 建立一种逻辑上的联系,即使 MyContainer<T> 并不实际存储 T 类型的值。
即使没有存储 u32,PhantomData<u32> 表明 MyContainer 是与 u32 绑定的。
let _instance2: MyContainer<u32> = MyContainer { _marker: PhantomData };
4.自定义关联
编译器知道 MyType 和 String 是关联的,即使没有存储数据。
let _instance3: MyType<String> = MyType::new();
二.DSL操作
DSL(Domain-Specific Language, 领域特定语言)是一种专注于特定问题领域的语言或语法,它通常嵌入在 Rust 代码中,用来更简洁、直观地描述领域问题。Rust 的 DSL 并非语言本身的内建特性,而是通过其强大的语法扩展能力(例如宏、属性宏、编译器插件等)实现的。
1.自定义DSL,在Rust里面嵌入类似于Html的语法操作,像 yew 或 maud 这样的框架使用宏创建 HTML DSL,这里的 DSL 模仿了 HTML 的结构,让开发者能以直观的方式编写模板。
//Cargo.toml引入
[dependencies]
maud = "0.24" # 确保使用最新的稳定版本
代码:
use maud::html;
fn main() {
let markup = html! {
html {
head {
title { "Hello, world!" }
}
body {
h1 { "This is a title" }
p { "This is a paragraph" }
}
}
};
markup.into_string());
}
运行的结果:
<html>
<head>
<title>Hello, world!</title>
</head>
<body><h1>This is a title</h1><p>This is a paragraph</p>
</body>
</html>
2.自定义命令行解析 ,这里的链式方法调用(如 .arg()、.about())构造了一个 DSL,描述命令行工具的配置。
运行输出结果:
#cargo run -- --config my_config.toml
warning: `/root/.cargo/config` is deprecated in favor of `config.toml`
note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
warning: `/root/.cargo/config` is deprecated in favor of `config.toml`
note: if you need to support cargo 1.38 or earlier, you can symlink `config` to `config.toml`
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/minglinghang --config my_config.toml`
Using config file: my_config.toml
3.自定义 DSL,实现一套自己认为美观的加减法:
macro_rules! calculate {
// 匹配加法
($a:expr, +, $b:expr) => {
$a + $b
};
// 匹配减法
($a:expr, -, $b:expr) => {
$a - $b
};
}
fn main() {
// 加法
let result_add = calculate!(5, +, 3);
println!("Result of 5 + 3: {}", result_add); // 输出: Result of 5 + 3: 8
// 减法
let result_sub = calculate!(10, -, 4);
println!("Result of 10 - 4: {}", result_sub); // 输出: Result of 10 - 4: 6
}
三.unsafe不安全操作
Rust虽然安全,但可以通过unsafe操作不安全的代码,没错它其实非常灵活。
fn main() {
let mut x = 5;
let ptr = &mut x as *mut i32;
unsafe {
*ptr = 10;
}
println!("x is now: {}", x);
}
三.极简线程池
利用迭代器和闭包,简化并发代码的结构。
use std::thread;
fn main() {
let handles: Vec<_> = (0..4).map(|i| {
thread::spawn(move || {
println!("Thread {} is running", i);
})
}).collect();
for handle in handles {
handle.join().unwrap();
}
}
四:生命周期
通过生命周期标注,可以避免不必要的数据拷贝并保证安全:
fn longest<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s1.len() > s2.len() {
s1
} else {
s2
}
}
fn main() {
let s1 = String::from("Rust");
let s2 = String::from("World");
println!("Longest: {}", longest(&s1, &s2));
}
结尾
以上列举了编译器魔法特性,DSL自定义,Unsafe不安全操作,极简线程池,生命周期等几大特性,但是实际上Rust里面深藏不露的特性远非这么多,不计以其数。通过这些特性,可以更好的,更快速的,更固安全的程序,
往期精彩回顾