我可以在循环中重置对本地的借用吗?
Can I reset a borrow of a local in a loop?
我有一个处理循环需要一个指向大型查找的指针 table。
不幸的是,该指针是从源数据三重间接指向的,因此在内部循环中保留该指针对于性能至关重要。
有什么方法可以告诉借用检查器我是 "unborrowing" 状态变量,万一我需要修改状态...所以我只能重新查找切片modify_state
函数触发的事件?
我想到的一个解决方案是将数据更改为切片引用并在函数开头对结构执行 mem::replace
并将切片拉入本地范围,然后将其替换回函数的结尾——但这非常脆弱且容易出错(因为我需要记住在每个 return 上替换该项目)。还有其他方法可以实现吗?
struct DoubleIndirect {
data: [u8; 512 * 512],
lut: [usize; 16384],
lut_index: usize,
}
#[cold]
fn modify_state(s: &mut DoubleIndirect) {
s.lut_index += 63;
s.lut_index %= 16384;
}
fn process(state: &mut DoubleIndirect) -> [u8; 65536] {
let mut ret: [u8; 65536] = [0; 65536];
let mut count = 0;
let mut data_slice = &state.data[state.lut[state.lut_index]..];
for ret_item in ret.iter_mut() {
*ret_item = data_slice[count];
if count % 197 == 196 {
data_slice = &[];
modify_state(state);
data_slice = &state.data[state.lut[state.lut_index]..];
}
count += 1
}
return ret;
}
最简单的方法是确保 state
的借用都是不相交的:
#[cold]
fn modify_state(lut_index: &mut usize) {
*lut_index += 63;
*lut_index %= 16384;
}
fn process(state: &mut DoubleIndirect) -> [u8; 65536] {
let mut ret: [u8; 65536] = [0; 65536];
let mut count = 0;
let mut lut_index = &mut state.lut_index;
let mut data_slice = &state.data[state.lut[*lut_index]..];
for ret_item in ret.iter_mut() {
*ret_item = data_slice[count];
if count % 197 == 196 {
modify_state(lut_index);
data_slice = &state.data[state.lut[*lut_index]..];
}
count += 1
}
return ret;
}
问题基本上有两点:首先,Rust 不会超越函数的签名来找出它做了什么。据编译器所知,您对 modify_state
的调用也可能会改变 state.data
,它不允许这样。
第二个问题是借词是词法;编译器查看借用 可能 的代码块。它(目前)不会尝试减少借用的长度以匹配它们实际活跃的地方。
你也可以玩游戏,例如,使用 std::mem::replace
将 state.data
拉出到一个局部变量中,做你的工作,然后 replace
它就在你 return.
我有一个处理循环需要一个指向大型查找的指针 table。 不幸的是,该指针是从源数据三重间接指向的,因此在内部循环中保留该指针对于性能至关重要。
有什么方法可以告诉借用检查器我是 "unborrowing" 状态变量,万一我需要修改状态...所以我只能重新查找切片modify_state
函数触发的事件?
我想到的一个解决方案是将数据更改为切片引用并在函数开头对结构执行 mem::replace
并将切片拉入本地范围,然后将其替换回函数的结尾——但这非常脆弱且容易出错(因为我需要记住在每个 return 上替换该项目)。还有其他方法可以实现吗?
struct DoubleIndirect {
data: [u8; 512 * 512],
lut: [usize; 16384],
lut_index: usize,
}
#[cold]
fn modify_state(s: &mut DoubleIndirect) {
s.lut_index += 63;
s.lut_index %= 16384;
}
fn process(state: &mut DoubleIndirect) -> [u8; 65536] {
let mut ret: [u8; 65536] = [0; 65536];
let mut count = 0;
let mut data_slice = &state.data[state.lut[state.lut_index]..];
for ret_item in ret.iter_mut() {
*ret_item = data_slice[count];
if count % 197 == 196 {
data_slice = &[];
modify_state(state);
data_slice = &state.data[state.lut[state.lut_index]..];
}
count += 1
}
return ret;
}
最简单的方法是确保 state
的借用都是不相交的:
#[cold]
fn modify_state(lut_index: &mut usize) {
*lut_index += 63;
*lut_index %= 16384;
}
fn process(state: &mut DoubleIndirect) -> [u8; 65536] {
let mut ret: [u8; 65536] = [0; 65536];
let mut count = 0;
let mut lut_index = &mut state.lut_index;
let mut data_slice = &state.data[state.lut[*lut_index]..];
for ret_item in ret.iter_mut() {
*ret_item = data_slice[count];
if count % 197 == 196 {
modify_state(lut_index);
data_slice = &state.data[state.lut[*lut_index]..];
}
count += 1
}
return ret;
}
问题基本上有两点:首先,Rust 不会超越函数的签名来找出它做了什么。据编译器所知,您对 modify_state
的调用也可能会改变 state.data
,它不允许这样。
第二个问题是借词是词法;编译器查看借用 可能 的代码块。它(目前)不会尝试减少借用的长度以匹配它们实际活跃的地方。
你也可以玩游戏,例如,使用 std::mem::replace
将 state.data
拉出到一个局部变量中,做你的工作,然后 replace
它就在你 return.