英文:
Passing mutable struct to mutable attribute of struct
问题
我正在使用 ratatui 构建一个小型 TUI 工具,我希望将一个可变的 App
实例传递给每个小部件,以便我可以:
- 处理事件并更新
widget
数据 - 更新主要的
App
数据
这是我工具的简单结构:
// app.rs
impl App {
pub fn new() -> Self {
Self {
user_input: UserInput::new(),
}
}
pub fn get_curr_widgets(&mut self) -> Vec<&mut dyn Component> {
vec![
&mut self.sidebar,
&mut self.user_input,
]
}
}
// src/components/user_input.rs
impl Component for UserInput {
fn handle_events(&mut self, event: Event, app: &mut App) {
match event {
Event::Key(key_event) => match key_event.code {
// 更新 App 数据
// KeyCode::Enter => app.do_search(),
// app.widget_index = -1
KeyCode::Char(to_insert) => {
// 更新 UserInput 数据
self.enter_char(to_insert);
}
_ => {}
},
_ => {}
}
}
}
// event_handles.rs
pub fn handle_terminal_events(event: Event, app: &mut App) {
let widget_index = app.widget_index;
let widgets = app.get_widgets();
for (index, widget) in app.get_widgets().into_iter().enumerate() {
if widget_index == index {
// 错误:error[E0499]: 不能同时多次借用 `*app` 为可变状态
widget.handle_events(event, app);
break;
}
}
}
完整错误信息:
error[E0499]: 不能同时多次借用 `*app` 为可变状态
--> src/handler.rs:51:43
|
48 | let widgets = app.get_widgets();
| --------------- 第一次可变借用发生在此处
...
51 | widget.handle_events(event, app);
| ------------- ^^^ 第二次可变借用发生在此处
| |
| 第一次借用稍后被调用
我对于这个问题的看法在于 widget.handle_events(event, app);
这一行:
widget.
首次可变借用了App
。- 随后我们无法将第二个可变引用传递给函数。
在 Rust 中,我们一次只能有一个可变引用。那么,有没有更好的方法来解决我的问题,或者我结构化错误?
英文:
I'm building a small TUI tool with ratatui, I want to pass a mutable instance of App
to every widget so I can:
- Handle events and update
widget
data - Update main
App
data
Here is a simple structure of my tool
// app.rs
impl App {
pub fn new() -> Self {
Self {
user_input: UserInput::new(),
}
}
pub fn get_curr_widgets(&mut self) -> Vec<&mut dyn Component> {
vec![
&mut self.sidebar,
&mut self.user_input,
]
}
}
// src/components/user_input.rs
impl Component for UserInput {
fn handle_events(&mut self, event: Event, app: &mut App) {
match event {
Event::Key(key_event) => match key_event.code {
// Update App data
// KeyCode::Enter => app.do_search(),
// app.widget_index = -1
KeyCode::Char(to_insert) => {
// Update UserInput data
self.enter_char(to_insert);
}
_ => {}
},
_ => {}
}
}
}
// event_handles.rs
pub fn handle_terminal_events(event: Event, app: &mut App) {
let widget_index = app.widget_index;
let widgets = app.get_widgets();
for (index, widget) in app.get_widgets().into_iter().enumerate() {
if widget_index == index {
// Error: error[E0499]: cannot borrow `*app` as mutable more than once at a time
widget.handle_events(event, app);
break;
}
}
}
Full error:
error[E0499]: cannot borrow `*app` as mutable more than once at a time
--> src/handler.rs:51:43
|
48 | let widgets = app.get_widgets();
| --------------- first mutable borrow occurs here
...
51 | widget.handle_events(event, app);
| ------------- ^^^ second mutable borrow occurs here
| |
| first borrow later used by call
What I think of the error at line: widget.handle_events(event, app);
widget.
first borrow mutable ofApp
- then we can't pass the second mutable of
App
to the function
In Rust, we only can have one mutable ref at a time.
So what are better ways to solve my problem or I'm structuring it wrong?
答案1
得分: 1
这似乎是一个设计问题。
Widgets(组件)被包含在App中,但您试图在组件级别处理事件时改变App。
理想情况下,改变App的代码应该存在于“impl App”块中。
impl App {
pub fn new() -> Self {
Self {
user_input: UserInput::new(),
}
}
pub fn handle_events(&mut self) {
let mut widgets = vec![
&mut self.sidebar,
&mut self.user_input,
];
for (index, widget) in self.get_widgets().iter_mut().enumerate() {
if widget_index == index {
widget.handle_events(event, self);
break;
}
}
}
}
// src/components/user_input.rs
impl Component for UserInput {
fn handle_events(&mut self, event: Event, app: &mut App) {
match event {
Event::Key(key_event) => match key_event.code {
// 更新App数据
// KeyCode::Enter => app.do_search(),
// app.widget_index = -1
KeyCode::Char(to_insert) => {
// 更新UserInput数据
self.enter_char(to_insert);
}
_ => {}
},
_ => {}
}
}
}
// event_handles.rs
pub fn handle_terminal_events(event: Event, app: &mut App) {
app.handle_events();
}
因此,通过此更改,您仅在App impl的上下文(生命周期)中改变了App。
这应该解决了问题。
注意:通常使用get方法来读取(&)而不是写入(&mut)。
英文:
This smells like a design problem.
Widgets (Components) are enclosed within App but you are trying to mutate the app when handling events at the Component level.
Ideally the code that mutates the App should exist within the "impl App" block.
impl App {
pub fn new() -> Self {
Self {
user_input: UserInput::new(),
}
}
pub fn handle_events(&mut self) {
let mut widgets = vec![
&mut self.sidebar,
&mut self.user_input,
];
for (index, widget) in self.get_widgets().iter_mut().enumerate() {
if widget_index == index {
widget.handle_events(event, self);
break;
}
}
}
}
// src/components/user_input.rs
impl Component for UserInput {
fn handle_events(&mut self, event: Event, app: &mut App) {
match event {
Event::Key(key_event) => match key_event.code {
// Update App data
// KeyCode::Enter => app.do_search(),
// app.widget_index = -1
KeyCode::Char(to_insert) => {
// Update UserInput data
self.enter_char(to_insert);
}
_ => {}
},
_ => {}
}
}
}
// event_handles.rs
pub fn handle_terminal_events(event: Event, app: &mut App) {
app.handle_events();
}
So by this change you are mutating the app within the context(lifetime) of App impl only.
This should resolve the issue.
NOTE: get methods are conventionally used to read(&) not write (&mut).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论