Как избежать клонирования «self» при вызове нескольких методов структуры в Rust?

я пытался вызвать два метода структуры, а именно 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
cafce25 03.09.2024 12:34
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

просто используйте &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> больше похож на общую ссылку, чем на изменяемую.

cafce25 03.09.2024 14:13

Другие вопросы по теме