я пытался вызвать два метода структуры, а именно self.bootstrap() и self.run(), внутри self.main(). Однако я получил предупреждение компилятора для self.run(), сказал use of moved value: self, value used here after move
Я считаю, что проблема в том, что self.bootstrap() взял на себя ответственность за self и не вернул его. таким образом, main больше не владеет собой, что вызывает проблему владения self.run()
структура и реализация FailedServer являются минимальным воспроизводимым примером этой ошибки.
mod minimal_example {
use std::{net::TcpStream, sync::Arc};
struct FailedServer {
nodes: Vec<String>,
}
impl FailedServer {
pub fn main(self: Arc<Self>) -> Result<(), Box<dyn std::error::Error>> {
self.bootstrap();
// the below `self.run()` with this compile error
// use of moved value: `self`
// value used here after move
self.run() // <- compiler error
}
fn bootstrap(self: Arc<Self>) {
let nodes = self.nodes.clone();
let len = nodes.len();
for i in 0..len {
let node = nodes[i].clone();
std::thread::spawn(move || {
TcpStream::connect(node);
});
}
}
fn run(self: Arc<Self>) -> Result<(), Box<dyn std::error::Error>> {
loop {
// a blocking loop to do something
}
Ok(())
}
}
}
я попытался клонировать self внутри main перед вызовом self.bootstrap() в примере ниже, и это сработало. Но мне это кажется странным, поскольку это будет означать, что если мне придется вызвать 10 различных методов структуры внутри main, мне придется клонировать self несколько раз, чтобы сохранить владение внутри main.
поэтому мой вопрос в том, действительно ли это правильный способ или это проблема моих навыков.
ниже приведен рабочий пример
mod minimal_example {
use std::{net::TcpStream, sync::Arc};
struct WorkableServer {
nodes: Vec<String>,
}
impl WorkableServer {
pub fn start(self: Arc<Self>) -> Result<(), Box<dyn std::error::Error>> {
self.clone().bootstrap();
self.run()
}
fn bootstrap(self: Arc<Self>) {
let nodes = self.nodes.clone();
let len = nodes.len();
for i in 0..len {
let node = nodes[i].clone();
println!("Bootstrapping to node: {}", node);
std::thread::spawn(move || {
TcpStream::connect(node);
});
}
}
fn run(self: Arc<Self>) -> Result<(), Box<dyn std::error::Error>> {
loop {
// a blocking loop to do something
}
Ok(())
}
}
}
self: Arc<Self> → &self
просто используйте &mut self вместо self, так как он не станет владельцем self.
mod mutable_reference {
struct Server;
impl Server {
pub fn start(mut self) {
self.startup();
self.config();
self.bootstrap();
self.init();
self.run()
}
pub fn startup(&mut self) {
println!("starting up . . .");
}
pub fn config(&mut self) {
println!("reading config . . .");
}
pub fn bootstrap(&mut self) {
println!("boostraping . . .");
}
pub fn init(&mut self) {
println!("initalizing . . .");
}
pub fn run(self) {
println!("running . . .");
loop { /* do re mi */ }
}
}
}
но если вы хотите, чтобы функция стала владельцем, верните Self(или Arc<Self> в вашем случае) в функцию, чтобы объединить разные функции.
mod take_ownership {
struct Server;
impl Server {
pub fn start(self) {
self
.startup()
.config()
.bootstrap()
.init()
.run()
}
pub fn startup(self) -> Self {
println!("starting up . . .");
self
}
pub fn config(self) -> Self {
println!("reading config . . .");
self
}
pub fn bootstrap(self) -> Self {
println!("boostraping . . .");
self
}
pub fn init(self) -> Self {
println!("initalizing . . .");
self
}
pub fn run(self) {
println!("running . . .");
loop { /* do re mi */ }
}
}
}
Зачем использовать изменяемую ссылку, если достаточно общей? Идиоматично использовать наименее ограничивающую ссылку, если это возможно. Кроме того, Arc<T> больше похож на общую ссылку, чем на изменяемую.