#rust
#Ржавчина
Вопрос:
Я пытаюсь сохранить a FnMut
в структуре:
struct OpenVPNSocket {
socket_send_callback: Option<Box<dyn FnMut(Vec<u8>) -> Result<(), ()>>>,
}
impl OpenVPNSocket {
fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()>>(amp;mut self, callback: Box<F>) {
self.socket_send_callback = Some(callback);
}
}
Я получаю эту ошибку:
error[E0310]: the parameter type `F` may not live long enough
--> src/lib.rs:8:42
|
7 | fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()>>(amp;mut self, callback: Box<F>) {
| -- help: consider adding an explicit lifetime bound...: `F: 'static `
8 | self.socket_send_callback = Some(callback);
| ^^^^^^^^ ...so that the type `F` will meet its required lifetime bounds
Я понимаю, что время жизни связано со ссылками. Однако я не использую ссылки. Я не понимаю, почему моя структура не может хранить a Box
. A Box
живет до тех пор, пока он используется.
Обновить:
У меня есть этот пример:
use std::sync::Arc;
pub type OnConsume = Arc<dyn Fn() -> Option<u8> Send Sync>;
struct Test {
callback: OnConsume
}
impl Test {
fn set_on_consume(amp;mut self, f: OnConsume) {
self.callback = f;
}
}
что работает. В чем отличие от предыдущего?
Ответ №1:
В Rust значения также имеют время жизни. Возьмем, к примеру, эту структуру:
struct RefWrapper<'a> {
some_ref: amp;'a u32
}
Экземпляр RefWrapper
не является ссылкой, но содержит время жизни. Поскольку вы перемещаете поле в структуру, которая может существовать в течение всего срока действия программы (метод не дает никаких гарантий относительно того, когда экземпляр struct может быть удален), функция должна существовать в течение максимального времени жизни, статического времени жизни.
Комментарии:
1. Если замыкание живет в течение более короткого срока службы, его можно аналогичным образом указать с помощью параметра lifetime, например
Box<dyn 'a FnMut...>
.2. Тогда его нельзя было бы переместить в struct, если бы тогда struct также не получил срок службы.
3. Абсолютно. Это то, что я имел в виду.
4. @Aplet123 вы можете посмотреть на мое обновление? Другой аналогичный обратный вызов работает без проблем при сохранении. Почему для этого у меня проблемы на всю жизнь?
Ответ №2:
Все объекты признаков имеют время жизни, неявное время жизни по умолчанию для объектов с признаками в штучной 'static
упаковке таково, что ваша структура socket_send_callback
фактически имеет неявную 'static
границу. Показано в контексте:
struct OpenVPNSocket {
socket_send_callback: Option<Box<dyn FnMut(Vec<u8>) -> Result<(), ()> 'static>>,
}
Поскольку объект в штучной упаковке должен быть ограничен 'static
временем жизни, когда вы пишете функцию для установки этого поля, само значение должно иметь 'static
время жизни, поэтому компилятор предлагает добавить эту явную привязку. Исправлен пример с добавленной привязкой:
impl OpenVPNSocket {
// notice the added 'static bound for F
fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()> 'static>(amp;mut self, callback: Box<F>) {
self.socket_send_callback = Some(callback);
}
}
С этим изменением ваш код будет скомпилирован. Если вы хотите принимать объекты признаков, которые не ограничены 'static
временем жизни, вы можете сделать это, создав свой OpenVPNSocket
общий по времени жизни. Это альтернативное решение также компилирует:
struct OpenVPNSocket<'a> {
socket_send_callback: Option<Box<dyn FnMut(Vec<u8>) -> Result<(), ()> 'a>>,
}
impl<'a> OpenVPNSocket<'a> {
fn set_socket_send<F: FnMut(Vec<u8>) -> Result<(), ()> 'a>(amp;mut self, callback: Box<F>) {
self.socket_send_callback = Some(callback);
}
}
Причина, по которой этот код работает, заключается в том, что вы определяете тип один раз и используете его в нескольких местах, и во всех местах он имеет неявную 'static
границу. Десугаринг:
use std::sync::Arc;
pub type OnConsume = Arc<dyn Fn() -> Option<u8> Send Sync 'static>;
struct Test {
callback: OnConsume
}
impl Test {
fn set_on_consume(amp;mut self, f: OnConsume) {
self.callback = f;
}
}
Однако вы можете сделать то же самое и в своем предыдущем коде:
type Callback = Box<dyn FnMut(Vec<u8>) -> Result<(), ()>>;
struct OpenVPNSocket {
socket_send_callback: Option<Callback>,
}
impl OpenVPNSocket {
fn set_socket_send(amp;mut self, callback: Callback) {
self.socket_send_callback = Some(callback);
}
}
Вышеупомянутое также компилируется, и неявная 'static
граница все еще существует.