我是Rust的新手,我目前面临的问题与subtyping and variance
概念有关(只是猜测,根据cargo
在构建时显示的帮助消息)。
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, mpsc, Mutex};
use std::thread;
trait Draw {
fn draw(&self);
}
#[derive(Default)]
struct Button {
}
impl Draw for Button {
fn draw(&self) {
println!("draw button");
}
}
#[derive(Default)]
struct SelectionBox {
}
impl Draw for SelectionBox {
fn draw(&self) {
println!("draw selection box");
}
}
#[derive(Default)]
struct TextField {
}
impl Draw for TextField {
fn draw(&self) {
println!("draw text field");
}
}
pub struct RunningThreadInterface<T> {
pub instance: Arc<T>,
pub thread_join_handle: thread::JoinHandle<()>,
}
pub trait StartThread<T> {
fn start(self, thread_id: String) -> RunningThreadInterface<T>;
fn run(&self);
}
pub trait TerminateThread {
fn stop(&mut self);
fn wait(self);
}
struct Screen<'a> {
widgets: Mutex<Vec<&'a (dyn Draw + Send + Sync)>>,
rx: Mutex<mpsc::Receiver<String>>,
terminate_flag: AtomicBool,
}
impl<'a> Screen<'a> {
fn new(rx: mpsc::Receiver<String>) -> Screen<'a> {
Screen {
widgets: Mutex::new(Vec::new()),
rx: Mutex::new(rx),
terminate_flag: AtomicBool::new(false),
}
}
fn add(&mut self, widget: &'a (dyn Draw + Send + Sync)) {
self.widgets.lock().unwrap().push(widget);
}
fn draw_widgets(&self) {
for widget in &*self.widgets.lock().unwrap() {
widget.draw();
}
}
}
impl<'a> StartThread<Screen<'a>> for Screen<'a> {
fn start(self, thread_id: String) -> RunningThreadInterface<Screen<'a>> {
let screen = Arc::new(self);
RunningThreadInterface {
instance: Arc::clone(&screen),
thread_join_handle: thread::Builder::new().name(thread_id).spawn(move || screen.run()).ok().unwrap(),
}
}
fn run(&self) {
while !self.terminate_flag.load(Ordering::SeqCst) {
self.rx.lock().unwrap().recv().unwrap();
}
}
}
impl<'a> TerminateThread for RunningThreadInterface<Screen<'a>> {
fn stop(&mut self) {
self.instance.terminate_flag.store(true, Ordering::SeqCst);
}
fn wait(self) {
self.thread_join_handle.join();
}
}
fn main() {
let button: Button = Default::default();
let selection_box: SelectionBox = Default::default();
let text_field: TextField = Default::default();
let (_tx, rx) = mpsc::channel();
let mut screen = Screen::new(rx);
screen.add(&button);
screen.add(&selection_box);
screen.add(&text_field);
screen.draw_widgets();
println!("");
button.draw();
selection_box.draw();
text_field.draw();
}
字符串
错误类型
error[E0521]: borrowed data escapes outside of method
--> src/main.rs:90:33
|
85 | impl<'a> StartThread<Screen<'a>> for Screen<'a> {
| -- lifetime `'a` defined here
86 | fn start(self, thread_id: String) -> RunningThreadInterface<Screen<'a>> {
| ---- `self` is a reference that is only valid in the method body
...
90 | thread_join_handle: thread::Builder::new().name(thread_id).spawn(move || screen.run()).ok().unwrap(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| `self` escapes the method body here
| argument requires that `'a` must outlive `'static`
|
= note: requirement occurs because of the type `Screen<'_>`, which makes the generic argument `'_` invariant
= note: the struct `Screen<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
For more information about this error, try `rustc --explain E0521`.
型
1条答案
按热度按时间hmtdttj41#
看起来这个问题是由传递一些变量给
thread::spawn
引起的,这要求接收到的变量具有'static
生命周期(因为编译器无法证明线程不会永远存在,也无法证明传递的引用在线程生命周期内是否正常)。我知道3种方法来解决当我们在稳定的Rust中向thread::spawn
传递具有非静态生命周期的变量时发生的问题start
中阻塞)字符串
thread::spawn
的变量需要静态生存期(我们希望避免)型
Drop
中完成执行(这很可能是作者想要的)型