rust - 不能在一个函数调用中借用 self 两次
问题描述
我是一个新手rust
,对函数调用感到震惊。很抱歉,我无法制作干净的错误示例,因为iced::PickList
.
问题是——只要我在该调用中只使用一种方法——构建过程和程序就可以工作,但是如果我只是将第二个需要的方法的签名更改为不是静态的——我根本无法构建和修复 bowwor 错误.
操场上的完整工作(构建和启动)示例。
虽然看起来像这样,但通过Self::port_names()
调用,它可以工作。
extern crate iced;
extern crate midir;
use std::cell::RefCell;
use std::error::Error;
use std::io::{stdin, stdout, Write};
use std::option::Option::Some;
use std::sync::mpsc::{channel, Sender};
use iced::{
button, executor, pick_list, scrollable, Align, Application, Button, Column, Command,
Container, Element, Length, PickList, Scrollable, Settings, Space, Text,
};
use midir::{Ignore, MidiInput, MidiInputConnection, MidiInputPort, MidiInputPorts};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
struct Port {
pub index: usize,
}
struct BigNote {
note: i32,
need_init: bool,
client_name: String,
scroll: scrollable::State,
ports_list: pick_list::State<Port>,
selected_port: Port,
connection: Option<MidiInputConnection<Sender<Vec<u8>>>>,
}
impl BigNote {
fn midi_in(&self) -> MidiInput {
MidiInput::new(&self.client_name.to_string()).unwrap()
}
fn ports_names() -> Vec<Port> { // this is static method
let mut names: Vec<Port> = Vec::new();
names.push(Port { index: 0 });
names.push(Port { index: 1 });
names.into()
}
}
impl Application for BigNote {
type Executor = executor::Default;
type Message = Message;
type Flags = ();
fn new(_flags: ()) -> (BigNote, Command<self::Message>) {
(
BigNote {
note: -1,
need_init: true,
client_name: String::from("MyBigNote"),
connection: Option::None,
ports_list: pick_list::State::<Port>::default(),
scroll: scrollable::State::default(),
selected_port: Port { index: 1 },
},
Command::none(),
)
}
fn view(&mut self) -> Element<Message> {
let pick_list = PickList::new(
&mut self.ports_list,
Self::ports_names(), // here is static method
Some(self.selected_port.clone()),
Message::PortSelected,
);
let mut content = Scrollable::new(&mut self.scroll)
.width(Length::Fill)
.align_items(Align::Center)
.spacing(10)
.push(Space::with_height(Length::Units(600)))
.push(Text::new("Which is your favorite String?"))
.push(pick_list);
content = content.push(Space::with_height(Length::Units(600)));
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}
如果我只是替换方法签名——问题从«不可变借用不能与可变一起执行»开始,直到«临时资源不能从函数返回»。
extern crate iced;
extern crate midir;
use std::cell::RefCell;
use std::error::Error;
use std::io::{stdin, stdout, Write};
use std::option::Option::Some;
use std::sync::mpsc::{channel, Sender};
use iced::{
button, executor, pick_list, scrollable, Align, Application, Button, Column, Command,
Container, Element, Length, PickList, Scrollable, Settings, Space, Text,
};
use midir::{Ignore, MidiInput, MidiInputConnection, MidiInputPort, MidiInputPorts};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
struct Port {
pub index: usize,
}
struct BigNote {
note: i32,
need_init: bool,
client_name: String,
scroll: scrollable::State,
ports_list: pick_list::State<Port>,
selected_port: Port,
connection: Option<MidiInputConnection<Sender<Vec<u8>>>>,
}
impl BigNote {
fn midi_in(&self) -> MidiInput {
MidiInput::new(&self.client_name.to_string()).unwrap()
}
fn ports_names(&self) -> Vec<Port> { // here is change
let mut names: Vec<Port> = Vec::new();
names.push(Port { index: 0 });
names.push(Port { index: 1 });
names.into()
}
}
impl Application for BigNote {
type Executor = executor::Default;
type Message = Message;
type Flags = ();
fn new(_flags: ()) -> (BigNote, Command<self::Message>) {
(
BigNote {
note: -1,
need_init: true,
client_name: String::from("MyBigNote"),
connection: Option::None,
ports_list: pick_list::State::<Port>::default(),
scroll: scrollable::State::default(),
selected_port: Port { index: 1 },
},
Command::none(),
)
}
fn view(&mut self) -> Element<Message> {
let pick_list = PickList::new(
&mut self.ports_list,
self.ports_names(), // and here
Some(self.selected_port.clone()),
Message::PortSelected,
);
let mut content = Scrollable::new(&mut self.scroll)
.width(Length::Fill)
.align_items(Align::Center)
.spacing(10)
.push(Space::with_height(Length::Units(600)))
.push(Text::new("Which is your favorite String?"))
.push(pick_list);
content = content.push(Space::with_height(Length::Units(600)));
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
}
请帮助我了解为什么会发生这种情况以及如何避免此类问题。
[编辑]
我觉得,我仍然没有得到 rust 中变量\局部变量的基本概念,因为当我将view
函数更改为:
fn view(&mut self) -> Element<Message> {
let port_names = self.ports_names(); // method call now here
let pick_list = PickList::new(
&mut self.ports_list,
port_names, // here only variable
Some(self.selected_port.clone()),
Message::PortSelected,
);
let mut content = Scrollable::new(&mut self.scroll)
.width(Length::Fill)
.align_items(Align::Center)
.spacing(10)
.push(Space::with_height(Length::Units(600)))
.push(Text::new("Which is your favorite String?"))
.push(pick_list);
content = content.push(Space::with_height(Length::Units(600)));
Container::new(content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
}
有效。我知道原因是 - 我将直接方法调用移至本地可行,但我自己看不出有什么区别......
解决方案
每当你有一个复合表达式,如结构构造函数或函数调用,
let pick_list = PickList::new(
&mut self.ports_list,
self.ports_names(), // and here
Some(self.selected_port.clone()),
Message::PortSelected,
);
对它的求值以一种非常具体的方式进行:首先,每个参数表达式都被求值,按照它们在源代码中的写入顺序,它们的值临时存储在堆栈中。然后,一旦所有参数值都准备好,就调用该函数。
在这种情况下:
&mut self.ports_list
首先评估并存储为临时值。现在,self.ports_list
是可变借来的。self.ports_names()
第二次被评估——但self.ports_list
被可变借用,并且调用ports_names
需要对所有self
的不可变借用,这是不允许的,因此会出现编译错误。在调用 的版本中
Self::ports_names()
,没有借用self
,所以这是允许的。Some(self.selected_port.clone())
在成功编译的版本中被评估为第三。这里,self.selected_port
是一个与不同的字段self.ports_list
,编译器知道它们可以安全地单独借用。
我将直接方法调用移至本地可行,但我自己看不出有什么区别......
通常,您可以在与其他借用的同时对结构的特定字段进行可变借用,但不能有与其他任何东西重叠的可变借用——并且方法调用总是借用整个结构,保证重叠。
第三个工作版本的重要区别不是self.ports_names()
存储在局部变量中,而是self.ports_names()
在评估之前 &mut self.ports_list
评估。局部变量只是为了方便实现这一点。
例如,如果PickList
是您的一种类型,您可以将其编写为结构文字而不是调用new()
函数,那么您可以按照不冲突的顺序编写字段初始值设定项:
let pick_list = PickList {
options: self.ports_names(),
selected: Some(self.selected_port.clone()),
on_selected: Message::PortSelected
// Write this last and it doesn't conflict with any temporary immutable borrows above.
state: &mut self.ports_list,
}
推荐阅读
- ruby-on-rails - 如何修复 AWS 弹性 beanstalkd 中的捆绑错误
- java - 在下面的一段 java 代码中获取 StackOverflowError
- swift - 如何在不覆盖最后一个字符的情况下设置 NSTextField 的最大长度?
- reactjs - TypeError:Object(...) is not a function in export Default
- command-line - 无法从命令行通过 hugo 创建新帖子
- python - Jupyter-notebook numpy.core.umath 导入失败
- java - 关于使用 smali 库的问题
- java - 如何在谷歌地图的多边形上绘制折线?
- c# - 如何在基础架构的 ASP.net MVC 网格中实现远程分页?
- mysql - JPA 实体未保存在数据库中