Rust 可变自内匹配表达式
我在Rust 可变自内匹配表达式,rust,Rust,我在match表达式中借用self时遇到问题: fn add_once(&'t mut self, p_name: &'t str) -> Box<Element> { match self.get(p_name) { Some(x) => Box::new(*x), None => self.add(p_name), } } 编译器拒绝此代码: error[E0502]:无法将“*self”作为可变
match
表达式中借用self
时遇到问题:
fn add_once(&'t mut self, p_name: &'t str) -> Box<Element> {
match self.get(p_name) {
Some(x) => Box::new(*x),
None => self.add(p_name),
}
}
编译器拒绝此代码:
error[E0502]:无法将“*self”作为可变项借用,因为它也是作为不可变项借用的
-->src/main.rs:38:21
|
36 |匹配自我获取(p|U名称){
|----此处发生不可变借用
37 |一些(x)=>Box::new(*x),
38 | None=>self.add(p|u name),
|^^^^^此处发生可变借用
39 | }
40 | }
|-不可变的借阅到此结束
我明白了,但我不知道如何重写match
表达式
在a中,通过让匹配
返回一个值,然后调用函数来解决这个问题。但是,这在这里不起作用,因为条件的含义不是选择一个值,而是有选择地执行一个操作
完整的代码示例如下:
struct Element<'e> {
name: &'e str,
}
impl<'e> Element<'e> {
fn new(p_name: &str) -> Element {
Element { name: p_name }
}
}
struct Top<'t> {
list: Vec<Element<'t>>,
}
impl<'t> Top<'t> {
fn new() -> Top<'t> {
Top { list: vec![] }
}
fn get(&self, p_name: &str) -> Option<&Element> {
for element in self.list.iter() {
if element.name == p_name {
return Some(element);
}
}
None
}
fn add(&'t mut self, p_name: &'t str) -> Box<Element> {
let new_element = Box::new(Element::new(p_name));
self.list.push(*new_element);
return new_element;
}
fn add_once(&'t mut self, p_name: &'t str) -> Box<Element> {
match self.get(p_name) {
Some(x) => Box::new(*x),
None => self.add(p_name),
}
}
}
fn main() {
let mut t = Top::new();
let plop1 = t.add_once("plop1");
let plop2 = t.add_once("plop1");
}
struct元素{
fn新(p_名称:&str)->元素{
元素{name:p_name}
}
}
结构顶部>,
}
恳求{
fn new()->Top让我们先解决设计问题。主要问题是生命周期合并:
struct Top<'t> {
list: Vec<Element<'t>>,
}
impl<'t> Top<'t> {
fn add(&'t mut self, p_name: &'t str) -> Box<Element>;
fn add_once(&'t mut self, p_name: &'t str) -> Box<Element>;
}
请注意,元素
的引用的生存期'a
不同于其包含的引用的生存期't
这样,就可以修复以下功能:
fn position(&self, p_name: &str) -> Option<usize> {
self.list.iter().position(|e| e.name == p_name)
}
fn add<'a>(&'a mut self, p_name: &'t str) -> &'a Element<'t> {
self.list.push(Element::new(p_name));
&self.list[self.list.len() - 1]
}
fn add_once<'a>(&'a mut self, p_name: &'t str) -> &'a Element<'t> {
if let Some(p) = self.position(p_name) {
return &self.list[p];
}
self.add(p_name)
}
我希望在一个完美的世界里,以下几点能够奏效:
fn add_once<'a>(&'a mut self, p_name: &'t str) -> &'a Element<'t> {
match self.get(p_name) {
Some(x) => x,
None => self.add(p_name)
}
}
fn add\u onceen即使没有可变错误,您仍然会有一个类型统一问题。match
的两个分支都应该返回相同的类型。同样,我感到惊讶的是,add
在您第一次将
推入向量然后返回时编译;然而,在我看来,推入向量应该无效te(移动)框的内容…不应该add
返回&Element
,而add\u once
的结果应该是&Element
?@MatthieuM.,它起作用是因为Element
是Copy
,所以*new\u Element
返回元素的副本。@Vladimitveev:啊,是的,我忘了Copy
不是然而,选择加入。不过,在我看来,这似乎表明了一个设计缺陷:Top
似乎应该是泛型的,并且可以处理非Copy
类型。我对锈迹非常陌生,所以可能存在设计错误。Top确实应该处理非Copy
类型。@MatthieuM。最初,我想要add
和add\u once
来恢复n&Element
,但无法使其工作。您在“完美世界”中完全正确备注。这不起作用,因为借词是词法的,但它们将来可能会变成非词法的,这将允许这种模式。据我所知,这是在libstd
的映射中引入Entry
API的主要原因之一(另一个原因当然是希望减少查找量)@VladimirMatveev:我希望它能得到扩展,在if
中使用无可辩驳的模式是一个很好的解决办法,但这意味着失去匹配@MatthieuM的详尽性检查。谢谢,我对生存期有了更多的了解。事实上,添加和添加一次返回的引用的生存期与元素本身。需要一点大脑训练,但看起来不错。然而,编译器抱怨fn@Tifauv“:很抱歉,fn在push
和index
之间不可能存在竞争条件吗?如果Vec.push
返回插入的元素,则会更简单。
fn position(&self, p_name: &str) -> Option<usize> {
self.list.iter().position(|e| e.name == p_name)
}
fn add<'a>(&'a mut self, p_name: &'t str) -> &'a Element<'t> {
self.list.push(Element::new(p_name));
&self.list[self.list.len() - 1]
}
fn add_once<'a>(&'a mut self, p_name: &'t str) -> &'a Element<'t> {
if let Some(p) = self.position(p_name) {
return &self.list[p];
}
self.add(p_name)
}
fn get<'a>(&'a self, p_name: &str) -> Option<&'a Element<'t>> {
self.position(p_name).map(|pos| &self.list[pos])
}
fn add_once<'a>(&'a mut self, p_name: &'t str) -> &'a Element<'t> {
match self.get(p_name) {
Some(x) => x,
None => self.add(p_name)
}
}