3个不稳定版本
0.2.0 | 2024年5月27日 |
---|---|
0.1.0 | 2024年4月25日 |
在 过程宏 中排名第1314
每月下载量32次
用于 structz
12KB
163 代码行
structz
Rust中匿名结构体实现
概述
安装
cargo add structz
创建与访问
use structz::*;
let age = 26;
let mut person = stru! {
name: "John Doe",
age, // captures the value of the variable with the same name
tags: vec!["developer", "rustacean"],
};
// immutable borrow
assert_eq!(field!(&person.name), &"John Doe");
// mutable borrow
*field!(&mut person.age) += 1;
assert_eq!(field!(&person.age), &27);
// consume the struct and get the field value
let tags = field!(person.tags);
assert_eq!(tags, vec!["developer", "rustacean"]);
// `person` cannot be used anymore.
注意:具有相同字段但字段顺序不同的匿名结构体被认为是同一类型的结构体。
use structz::*;
let rect1 = stru! { width: 1920, height: 1080 };
let rect2 = stru! { height: 1080, width: 1920 };
assert_eq!(rect1, rect2);
作为参数
use structz::*;
fn print_person(person: stru_t! {name: &str, age: u8, tags: Vec<&str> }) {
println!(
"{} is {} years old and has tags {:?}",
field!(&person.name),
field!(&person.age),
field!(&person.tags)
);
}
let person = stru! {
tags: vec!["programmer", "artist"],
name: "Alice",
age: 30,
};
print_person(person);
更好的方法是使用named_args
宏,它可以帮助您解构结构体
use structz::*;
#[named_args]
fn print_person(name: &str, age: u8, tags: Vec<&str>) {
println!("{} is {} years old and has tags {:?}", name, age, tags);
}
let person = stru! {
tags: vec!["programmer", "artist"],
name: "Alice",
age: 30,
};
print_person(person);
通过subseq()
方法(来自tuplez),您可以获取匿名结构体的子结构体
use structz::*;
use tuplez::TupleLike;
#[named_args]
fn print_person(name: &str, age: u8) {
println!("{} is {} years old", name, age);
}
let alice = stru! {
jobs: "programmer",
name: "Alice",
age: 30,
children: vec!["Bob"],
};
print_person(alice.subseq());
let bob = stru! {
name: "Bob",
parent: vec!["Alice", "John"],
age: 7,
grade: 1,
};
print_person(bob.subseq());
let empty = stru! {
name: "**Empty**",
age: 0,
};
print_person(empty.subseq()); // Of course it is a sub-struct of itself
作为泛型类型
use stringz::ident;
use structz::*;
// `R1` and `R2` are "magic", used to indicate the position of the field in the structs,
// and these magic generic types will be automatically inferred by Rust.
// You should introduce a magic generic type for each field.
fn print_name_id<T, R1, R2>(any: &T)
where
T: HasField<ident!(name), &'static str, R1>,
T: HasField<ident!(id), usize, R2>,
{
println!("{}", field!(&any.name));
println!("{}", field!(&any.id));
}
let person = stru! {
name: "John",
age: 15,
id: 1006,
jobs: "Programmer",
};
let earth = stru! {
name: "Earth",
id: 3,
galaxy: "Sol",
satellites: vec!["Moon"],
};
print_name_id(&person);
print_name_id(&earth);
详细信息
首先,宏按字典顺序排序输入字段,这确保了具有相同字段但字段顺序不同的匿名结构体是同一类型的。
其次,通过stringz将字段名称转换为由一系列零大小类型组成的专用类型。我们称它们为“字段名称类型”。
最后,将字段名称类型和每个字段的类型数据打包,并将它们组合成Tuple
(来自tuplez)。
由于字段名称实际上被替换为零大小类型,所以这不会给您带来任何成本
use structz::*;
assert_eq!(
std::mem::size_of::<
stru_t! {
age: u8,
name: &'static str,
tags: Vec<&'static str>,
},
>(),
std::mem::size_of::<(u8, &'static str, Vec<&'static str>)>()
);
依赖关系
~275–720KB
~17K SLoC