背景
我对 Rust 相当陌生,我正在尝试编写一个数据包解析器。它位于没有堆的 #[no_std]
环境中。
解析器的输入是对字节切片的可变引用 (&mut [u8]
),输出是数据包头的 heapless::Vec
结构(实际上每个只是一个结构,带有对其切片的引用和一些用于获取 header 字段的函数)。
问题
我正在努力将初始提供的切片拆分为各个数据包 header 所需的较小切片。在函数中借用切片并使用 slice.take_mut()
获取第一 block 似乎不会返回切片其余部分的权限,因此对该函数的第二次调用无法编译。
我还尝试过使用 slice.split_at_mut()
实现类似的问题。
我正在努力理解生命周期以及它们如何融入这一切,这无济于事。
示例
我尝试将代码简化为最小的示例,但这样做可能会错过一些重要的上下文。
#![feature(slice_take)]
fn main() {
let mut bytes: [u8; 30] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
];
let mut s1 = MyStruct::from_bytes(&mut bytes).unwrap();
let mut s2 = MyStruct::from_bytes(&mut bytes).unwrap();
println!("{:?}", s1);
println!("{:?}", s2);
println!("{:?}", bytes);
}
#[derive(Debug)]
struct MyStruct<'a> {
data: &'a mut [u8], // This should be a 10-byte slice.
}
impl<'a> MyStruct<'a> {
fn from_bytes(mut data: &'a mut [u8]) -> Result<MyStruct<'a>, &'static str> {
if data.len() < 10 {
return Err("Need 10 bytes.");
}
let struct_data = data.take_mut(..10).unwrap();
Ok(MyStruct{data: struct_data})
}
}
我所期待的:
MyStruct { data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] }
MyStruct { data: [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] }
[21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
实际发生的情况:
error[E0499]: cannot borrow `bytes` as mutable more than once at a time
--> src\main.rs:10:39
|
9 | let mut s1 = MyStruct::from_bytes(&mut bytes).unwrap();
| ---------- first mutable borrow occurs here
10 | let mut s2 = MyStruct::from_bytes(&mut bytes).unwrap();
| ^^^^^^^^^^ second mutable borrow occurs here
11 | println!("{:?}", s1);
| -- first borrow later used here
最佳答案
你已经很接近了,但是你有两个问题。
首先是 from_bytes
需要获取对可变切片的可变引用。这允许它将调用者提供的切片设置为子区域。
第二个是您传递的是 &mut bytes
而不是切片 - 您需要传入对切片的可变引用,以便 from_bytes
可以调整该引用切片以指向子区域。
解决这两个问题:
#![feature(slice_take)]
fn main() {
let mut bytes: [u8; 30] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
];
let mut b = &mut bytes[..];
let s1 = MyStruct::from_bytes(&mut b).unwrap();
let s2 = MyStruct::from_bytes(&mut b).unwrap();
println!("{:?}", s1);
println!("{:?}", s2);
println!("{:?}", b);
}
#[derive(Debug)]
struct MyStruct<'a> {
data: &'a mut [u8], // This should be a 10-byte slice.
}
impl<'a> MyStruct<'a> {
fn from_bytes(data: &mut &'a mut [u8]) -> Result<MyStruct<'a>, &'static str> {
if data.len() < 10 {
return Err("Need 10 bytes.");
}
let struct_data = data.take_mut(..10).unwrap();
Ok(MyStruct{data: struct_data})
}
}
( Playground )
请注意,您可以使用 split_at_mut
来在稳定的 Rust 上实现此操作。这需要一些涉及 std::mem::take()
的技巧——事实上,这正是 take_mut
的底层实现方式!
fn main() {
let mut bytes: [u8; 30] = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
];
let mut b = &mut bytes[..];
let s1 = MyStruct::from_bytes(&mut b).unwrap();
let s2 = MyStruct::from_bytes(&mut b).unwrap();
println!("{:?}", s1);
println!("{:?}", s2);
println!("{:?}", b);
}
#[derive(Debug)]
struct MyStruct<'a> {
data: &'a mut [u8], // This should be a 10-byte slice.
}
impl<'a> MyStruct<'a> {
fn from_bytes(data: &mut &'a mut [u8]) -> Result<MyStruct<'a>, &'static str> {
if data.len() < 10 {
return Err("Need 10 bytes.");
}
let (struct_data, tail) = std::mem::take(data).split_at_mut(10);
*data = tail;
Ok(MyStruct{data: struct_data})
}
}
( Playground )
关于rust - 如何在函数中借用 "take"切片的第一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76003226/