如何将变量存储在特征中,以便它可以在特征的其他方法中使用?
How can I store variables in traits so that it can be used in other methods on trait?
我的代码中有几个具有共同功能的对象。这些对象本质上就像服务一样,它们有一个生命周期(由 start/stop 控制)并执行工作直到它们的生命周期结束。我正在尝试重构我的代码以减少重复但卡住了。
在高层次上,我的对象都实现了下面的代码。
impl SomeObject {
fn start(&self) {
// starts a new thread.
// stores the 'JoinHandle' so thread can be joined later.
}
fn do_work(&self) {
// perform work in the context of the new thread.
}
fn stop(&self) {
// interrupts the work that this object is doing.
// stops the thread.
}
}
本质上,这些对象就像“服务”一样,所以为了重构,我的第一个想法是我应该创建一个名为“服务”的特征,如下所示。
trait Service {
fn start(&self) {}
fn do_work(&self);
fn stop(&self) {}
}
然后,我可以更新我的对象以实现“服务”特性。我遇到的问题是,由于不允许特征具有 fields/properties,我不确定如何在特征中保存 'JoinHandle' 以便我可以在其他方法。
在 Rust 中是否有惯用的方法来处理这个问题?
tldr;如何将变量保存在特征中,以便它们可以在不同的特征方法中重复使用?
编辑:
这是我确定的解决方案。感谢任何反馈。
extern crate log;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread::JoinHandle;
pub struct Context {
name: String,
thread_join_handle: JoinHandle<()>,
is_thread_running: Arc<AtomicBool>,
}
pub trait Service {
fn start(&self, name: String) -> Context {
log::trace!("starting service, name=[{}]", name);
let is_thread_running = Arc::new(AtomicBool::new(true));
let cloned_is_thread_running = is_thread_running.clone();
let thread_join_handle = std::thread::spawn(move || loop {
while cloned_is_thread_running.load(Ordering::SeqCst) {
Self::do_work();
}
});
log::trace!("started service, name=[{}]", name);
return Context {
name: name,
thread_join_handle: thread_join_handle,
is_thread_running: is_thread_running,
};
}
fn stop(context: Context) {
log::trace!("stopping service, name=[{}]", context.name);
context.is_thread_running.store(false, Ordering::SeqCst);
context
.thread_join_handle
.join()
.expect("joining service thread");
log::trace!("stopped service, name=[{}]", context.name);
}
fn do_work();
}
我认为您只需要将 JoinHandle 保存在结构的状态本身中,然后其他方法也可以访问它,因为它们都已经获得了传递给它们的所有结构数据。
struct SomeObject {
join_handle: JoinHandle;
}
impl Service for SomeObject {
fn start(&mut self) {
// starts a new thread.
// stores the 'JoinHandle' so thread can be joined later.
self.join_handle = what_ever_you_wanted_to_set //Store it here like this
}
fn do_work(&self) {
// perform work in the context of the new thread.
}
fn stop(&self) {
// interrupts the work that this object is doing.
// stops the thread.
}
}
希望对你有用。
根据您使用特征的方式,您可以重组代码并使其开始 returns JoinHandle,其他函数将连接句柄作为输入
trait Service {
fn start(&self) -> JoinHandle;
fn do_work(&self, handle: &mut JoinHandle);
fn stop(&self, handle: JoinHandle);
}
(可能根据您的需要使用不同的函数参数)。通过这种方式,您可以通过将所有处理句柄(哈哈)的代码放在结构本身之外并使其更通用来减少重复代码。如果您希望结构在此特征之外使用 JoinHandle,我会说最好按照 Equinox 的建议进行操作,并将其设为一个字段。
我的代码中有几个具有共同功能的对象。这些对象本质上就像服务一样,它们有一个生命周期(由 start/stop 控制)并执行工作直到它们的生命周期结束。我正在尝试重构我的代码以减少重复但卡住了。
在高层次上,我的对象都实现了下面的代码。
impl SomeObject {
fn start(&self) {
// starts a new thread.
// stores the 'JoinHandle' so thread can be joined later.
}
fn do_work(&self) {
// perform work in the context of the new thread.
}
fn stop(&self) {
// interrupts the work that this object is doing.
// stops the thread.
}
}
本质上,这些对象就像“服务”一样,所以为了重构,我的第一个想法是我应该创建一个名为“服务”的特征,如下所示。
trait Service {
fn start(&self) {}
fn do_work(&self);
fn stop(&self) {}
}
然后,我可以更新我的对象以实现“服务”特性。我遇到的问题是,由于不允许特征具有 fields/properties,我不确定如何在特征中保存 'JoinHandle' 以便我可以在其他方法。
在 Rust 中是否有惯用的方法来处理这个问题?
tldr;如何将变量保存在特征中,以便它们可以在不同的特征方法中重复使用?
编辑:
这是我确定的解决方案。感谢任何反馈。
extern crate log;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread::JoinHandle;
pub struct Context {
name: String,
thread_join_handle: JoinHandle<()>,
is_thread_running: Arc<AtomicBool>,
}
pub trait Service {
fn start(&self, name: String) -> Context {
log::trace!("starting service, name=[{}]", name);
let is_thread_running = Arc::new(AtomicBool::new(true));
let cloned_is_thread_running = is_thread_running.clone();
let thread_join_handle = std::thread::spawn(move || loop {
while cloned_is_thread_running.load(Ordering::SeqCst) {
Self::do_work();
}
});
log::trace!("started service, name=[{}]", name);
return Context {
name: name,
thread_join_handle: thread_join_handle,
is_thread_running: is_thread_running,
};
}
fn stop(context: Context) {
log::trace!("stopping service, name=[{}]", context.name);
context.is_thread_running.store(false, Ordering::SeqCst);
context
.thread_join_handle
.join()
.expect("joining service thread");
log::trace!("stopped service, name=[{}]", context.name);
}
fn do_work();
}
我认为您只需要将 JoinHandle 保存在结构的状态本身中,然后其他方法也可以访问它,因为它们都已经获得了传递给它们的所有结构数据。
struct SomeObject {
join_handle: JoinHandle;
}
impl Service for SomeObject {
fn start(&mut self) {
// starts a new thread.
// stores the 'JoinHandle' so thread can be joined later.
self.join_handle = what_ever_you_wanted_to_set //Store it here like this
}
fn do_work(&self) {
// perform work in the context of the new thread.
}
fn stop(&self) {
// interrupts the work that this object is doing.
// stops the thread.
}
}
希望对你有用。
根据您使用特征的方式,您可以重组代码并使其开始 returns JoinHandle,其他函数将连接句柄作为输入
trait Service {
fn start(&self) -> JoinHandle;
fn do_work(&self, handle: &mut JoinHandle);
fn stop(&self, handle: JoinHandle);
}
(可能根据您的需要使用不同的函数参数)。通过这种方式,您可以通过将所有处理句柄(哈哈)的代码放在结构本身之外并使其更通用来减少重复代码。如果您希望结构在此特征之外使用 JoinHandle,我会说最好按照 Equinox 的建议进行操作,并将其设为一个字段。