提问人:Guy 提问时间:8/18/2022 最后编辑:Chayim FriedmanGuy 更新时间:8/18/2022 访问量:42
Rust 不可变借用,然后以相同的方法改变代码
Rust immutable borrow followed by mutating code in a same method
问:
这是我目前正在构建的 Font 对象的简化版本,用于包含在嵌入式系统中。在 Font 中,我通过 HashMap 实现了已经栅格化的字形的缓存。retrieve() 方法必须首先通过 find() 方法检查缓存中是否已有特定字形。如果未找到,则必须构建字形,将其放入缓存中,然后将其返回给调用方。
问题在于,如果找不到所需的字形,retrieve() 方法必须首先执行不可变借用,然后才能修改缓存。找不到让它正常工作的方法。代码如下:
use std::collections::HashMap;
use std::collections::hash_map::RandomState;
type GlyphCharCode = u32;
type GlyphsCache = HashMap<GlyphCharCode, Glyph, RandomState>;
struct Glyph { a: u8 }
struct Font {
cache: GlyphsCache
}
impl Font {
fn new() -> Font {
Font { cache: GlyphsCache::new() }
}
fn find(&self, charcode: GlyphCharCode) -> Option<&Glyph> {
self.cache.get(&charcode)
}
fn retrieve(&mut self, charcode: GlyphCharCode) -> Option<&Glyph> {
let result = self.find(charcode);
match result {
Some(glyph) => Some(glyph),
None => { self.cache.insert(charcode, Glyph { a: 3u8 });
self.find(charcode) }
}
}
}
fn main() {
let charcode: GlyphCharCode = 3;
let mut font = Font::new();
if let Some(glyph) = font.retrieve(charcode) {
println!("Glyph value: {}", glyph.a);
}
}
以下是错误消息:
error[E0502]: cannot borrow `self.cache` as mutable because it is also borrowed as immutable
--> src/main.rs:26:17
|
22 | fn retrieve(&mut self, charcode: GlyphCharCode) -> Option<&Glyph> {
| - let's call the lifetime of this reference `'1`
23 | let result = self.find(charcode);
| ------------------- immutable borrow occurs here
24 | match result {
25 | Some(glyph) => Some(glyph),
| ----------- returning this value requires that `*self` is borrowed for `'1`
26 | None => { self.cache.insert(charcode, Glyph { a: 3u8 });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
答:
3赞
Silvio Mayolo
8/18/2022
#1
您可以使用 的入口
API 来实现“借用否则”模式。HashMap
fn retrieve(&mut self, charcode: GlyphCharCode) -> &mut Glyph {
self.cache.entry(charcode).or_insert(Glyph { a: 3u8 })
}
这与您尝试执行的操作完全相同:“如果存在,请返回,或者填写并返回,否则”,但它内置于 .HashMap
您可以考虑使用 or_insert_with
,它采用一个闭包,只有在实际需要插入时才会调用该闭包,并且在您的用例中构造成本很高。
fn retrieve(&mut self, charcode: GlyphCharCode) -> &mut Glyph {
self.cache.entry(charcode).or_insert_with(|| Glyph { a: 3u8 })
}
此外,如果真的那么简单,它应该是,我们可以完全放弃整个生命周期的问题。Glyph
Copy
#[derive(Copy)]
struct Glyph { a: u8 }
然后可以按值返回。find
fn find(&self, charcode: GlyphCharCode) -> Option<Glyph> {
self.cache.get(&charcode).copied()
}
无需生命周期。
评论
0赞
Guy
8/18/2022
感谢西尔维奥的帮助。Glyph 对象比此处显示的要复杂得多,创建它需要使用 freetype 库。我会看看你的建议,并尝试用它做点什么。再次感谢!
0赞
Silvio Mayolo
8/18/2022
@Guy我认为为了我们的利益,它可能会最小化。在这种情况下,该方法应该适合您。您可能还想使用or_insert_with
而不是建筑成本高昂(我现在将其编辑到我的答案中)entry
or_insert
0赞
Guy
8/18/2022
我刚刚找到它!!谢谢。我将进行一些测试并将其标记为已解决。多谢!!
评论