gpt4 book ai didi

collections - 迭代时无法分配给不可变的索引内容

转载 作者:行者123 更新时间:2023-11-29 08:12:40 26 4
gpt4 key购买 nike

我正在用 Rust 为 Java 应用程序编写一个库,我正在尝试将数据从 Java 代码发送到 Rust 代码。此数据由我在 Rust 端构建的名为 Chunk 的结构组成。我还发送数据来修改这些结构,因此它们需要是可变的。我收到一条错误消息,指出 HashSet 中的 Chunk 是不可变的,但事实并非如此。

#[derive(Eq, PartialEq, Hash)]
struct Chunk {
x: i32,
y: i32,
z: i32,
blocks: [[[i32; 16]; 16]; 16],
}

lazy_static! {
// static mutable list (or at least it should be)
static ref CHUNKS: Mutex<HashSet<Chunk>> = Mutex::new(HashSet::new());
}

#[no_mangle]
pub extern fn add_chunk(cx: i32, cy: i32, cz: i32, c_blocks: [[[i32; 16]; 16]; 16]) {
// create Chunk and put it in the global list
CHUNKS.lock().unwrap().insert(Chunk {x: cx, y: cy, z: cz, blocks: c_blocks});
}

#[no_mangle]
pub extern fn update_block(x: i32, y: i32, z: i32, id: i32) {
let cx: i32 = x / 16;
let cy: i32 = y / 16;
let cz: i32 = z / 16;

let rx: i32 = if x > 0 { x % 16 } else { 16 + (x % 16) };
let ry: i32 = if y > 0 { y % 16 } else { 16 + (y % 16) };
let rz: i32 = if z > 0 { z % 16 } else { 16 + (z % 16) };

for c in CHUNKS.lock().unwrap().iter() {
if c.x == cx && c.y == cy && c.z == cz {

// ERROR: cannot assign to immutable indexed content `c.blocks[..][..][..]`

c.blocks[rx as usize][ry as usize][rz as usize] = id;
}
}
}

我不知道我应该使用 Vec 还是 HashSet,我选择了后者,因为它似乎最简单。

最佳答案

原答案不正确 - HashSet没有 iter_mut()方法:改变哈希表的元素是不安全的,因为它们的位置是由它们的哈希决定的,所以如果一个值改变,它的哈希也会改变,但由于它是就地修改的,它不会在哈希表中定位不再正确,并且可能会丢失。

因此,最自然的方法是使用 HashMap<(i32, i32, i32), Chunk> ,正如@starblue 所建议的那样:

lazy_static! {
static ref CHUNKS: Mutex<HashMap<(i32, i32, i32), Chunk>> = Mutex::new(HashMap::new());
}

#[no_mangle]
pub extern fn add_chunk(cx: i32, cy: i32, cz: i32, c_blocks: [[[i32; 16]; 16]; 16]) {
CHUNKS.lock().unwrap().insert((cx, cy, cz), Chunk {x: cx, y: cy, z: cz, blocks: c_blocks});
}

#[no_mangle]
pub extern fn update_block(x: i32, y: i32, z: i32, id: i32) {
let cx: i32 = x / 16;
let cy: i32 = y / 16;
let cz: i32 = z / 16;

let guard = CHUNKS.lock().unwrap();
if let Some(chunk) = guard.get_mut((cx, cy, cz)) {
let rx: i32 = if x > 0 { x % 16 } else { 16 + (x % 16) };
let ry: i32 = if y > 0 { y % 16 } else { 16 + (y % 16) };
let rz: i32 = if z > 0 { z % 16 } else { 16 + (z % 16) };

chunk.blocks[rx as usize][ry as usize][rz as usize] = id;
}
}

此外,使用 HashMap ,您无需遍历整个集合即可通过其坐标获取项目。

原答案如下。


你的代码几乎是正确的,你只需要使用iter_mut()而不是 iter() :

for c in CHUNKS.lock().unwrap().iter_mut()

或者,或者:

for c in &mut *CHUNKS.lock().unwrap()

iter()返回一个产生不可变引用的迭代器,所以你不能通过它修改任何东西。 iter_mut() ,另一方面,返回一个产生可变引用的迭代器——正是您所需要的。

此外,不是直接调用 iter_mut() , 依赖 IntoIterator 更为惯用集合引用的实现:例如,&mut HashSet<T>工具 IntoIterator调用iter_mut()在片场,所以for x in &mut hash_set相当于for x in hash_set.iter_mut() .附加*这里是必需的,因为 unwrap()不仅返回包含的值,还返回 MutexGuard它取消引用互斥体包含的任何内容。

关于collections - 迭代时无法分配给不可变的索引内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35691109/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com