10 个版本
0.3.6 | 2024 年 7 月 21 日 |
---|---|
0.3.5 | 2024 年 7 月 21 日 |
0.3.1 | 2024 年 4 月 23 日 |
0.2.1 | 2024 年 4 月 22 日 |
0.1.0 | 2024 年 4 月 21 日 |
#499 in Rust 模式
100 个月下载量
在 3 个包中使用了(通过 error_set_impl)
54KB
1K SLoC
Indices
Indices 提供了用于从 可变切片 中安全地检索 多个可变元素 的宏和方法,针对切片元素通常需要 RefCell
或 Cell
(内部可变性方法)的场景。
例如:
let (four, one, two) = indices!(slice, 4, 1, 2);
这将展开为:
#[inline(always)]
fn func<T>(slice: &mut [T], one: usize, two: usize, three: usize,) -> (&mut T, &mut T, &mut T) {
if one == two || one == three || two == three {
panic!("Duplicate indices are not allowed.");
}
let slice_len = slice.len();
if one >= slice_len || two >= slice_len || three >= slice_len {
panic!("Index out of bounds.");
}
let ptr = slice.as_mut_ptr();
unsafe { (&mut *ptr.add(one), &mut *ptr.add(two), &mut *ptr.add(three)) }
}
let (four, one, two) = func(slice, 4, 1, 2);
这将由 Rust 编译器优化为以下伪代码:
if 4 >= slice.len() {
panic!("Index out of bounds.");
}
let (four, one, two) = (&mut slice[4], &mut slice[1], &mut slice[2])
以上代码是安全的、正确的,并且比使用 RefCell
或 Cell
更高效。`indices!` 会按照上述展开模式进行最多 4 个请求的索引。在这一点上,宏将切换到针对许多请求的索引的更优化方法。
还有 `try_indices!`、`indices_ordered!` 和 `try_indices_ordered!`。
示例
宏示例
所有宏都是零分配,允许在运行时检索可变数量的索引。当索引数量在编译时已知时,请首选宏。例如:
fn main() {
struct Person {
first: String,
last: String,
}
let mut data = [
Person { first: "John".to_string(), last: "Doe".to_string() },
Person { first: "Jane".to_string(), last: "Smith".to_string() },
Person { first: "Alice".to_string(), last: "Johnson".to_string() },
Person { first: "Bob".to_string(), last: "Brown".to_string() },
Person { first: "Charlie".to_string(), last: "White".to_string() },
];
fn modify(data_slice: &mut [Person], index: usize){
let (four, func_provided, three) = indices!(data_slice, 4, index, 3);
four.last = "Black".to_string();
func_provided.first = "Jack".to_string();
three.last = "Jones".to_string();
}
let slice = data.as_mut_slice();
modify(slice, 1);
assert_eq!(data[4].last, "Black");
assert_eq!(data[1].first, "Jack");
assert_eq!(data[3].last, "Jones");
}
方法示例
当在编译时不知道索引数量时,方法允许更动态的运行时检索。例如:
fn main() {
struct Node {
index: usize,
visited: usize,
edges: Vec<usize>,
message: String,
}
let mut graph = vec![
Node {
index: 0,
visited: usize::MAX,
edges: vec![1, 2],
message: String::new(),
},
Node {
index: 1,
visited: usize::MAX,
edges: vec![0, 2],
message: String::new(),
},
Node {
index: 2,
visited: usize::MAX,
edges: vec![3],
message: String::new(),
},
Node {
index: 4,
visited: usize::MAX,
edges: vec![1],
message: String::new(),
},
];
fn traverse_graph(graph: &mut [Node], current: usize, start: usize) -> bool {
if current == start {
return true;
}
let edges = graph[current].edges.clone();
let [mut current_node, mut edge_nodes] = indices_slices(graph, [&[current], &edges]);
for edge_node in edge_nodes.iter_mut() {
current_node[0].visited = current;
edge_node.message.push_str(&format!(
"This is Node `{}` Came from Node `{}`.",
edge_node.index, current_node[0].visited
));
}
for edge in edges {
if traverse_graph(graph, edge, start) {
return true;
}
}
return false;
}
traverse_graph(&mut *graph, 2, 0);
let answers = [
"This is Node `0` Came from Node `1`.",
"This is Node `1` Came from Node `3`.",
"This is Node `2` Came from Node `1`.",
"This is Node `4` Came from Node `2`.",
];
for (index, node) in graph.iter().enumerate() {
assert_eq!(&node.message, answers[index]);
}
}