#rust #object-lifetime
#Ржавчина #объект-время жизни
Вопрос:
Мне снова удалось столкнуться с проблемой на всю жизнь, которую я, похоже, не могу решить самостоятельно.
У меня есть эта черта
pub trait MiddlewareHandler: Clone {
fn invoke (amp;self, req: amp;Request, res: amp;mut Response) -> bool {
true
}
// we need this because otherwise clone() would be ambiguous
fn clone_box(amp;self) -> Box<MiddlewareHandler> {
box self.clone() as Box<MiddlewareHandler>
}
}
impl MiddlewareHandler for fn (req: amp;Request, res: amp;mut Response) -> bool {
fn invoke(amp;self, req: amp;Request, res: amp;mut Response) -> bool{
(*self).invoke(req, res)
}
}
impl Clone for Box<MiddlewareHandler> {
fn clone(amp;self) -> Box<MiddlewareHandler> {
self.clone_box()
}
}
Это я реализую для fn (req: amp;Request, res: amp;mut Response) -> bool
того, чтобы иметь возможность одновременно использовать accept облегченные функции и более тяжелые MiddlewareHandler
средства реализации.
Я сохраняю их как Vec<Box<MiddlewareHandler>>
pub struct Middleware {
handlers: Vec<Box<MiddlewareHandler>>
}
Теперь проблема в том, что компилятор кричит на меня прямо здесь:
pub fn add<T: MiddlewareHandler> (amp;mut self, handler: T) {
self.handlers.push(box handler);
}
В нем говорится:
error: value may contain references; add `'static` bound to `T`
self.handlers.push(box handler);
Реализация должна быть очень похожа на используемую здесь:
https://github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67
Однако, похоже, я не вижу разницы :-/
Если кто-нибудь захочет помочь мне, я отправил код на github в static
ветку:
Ответ №1:
Проблема здесь в том, что для безопасного создания объекта в штучной упаковке исходный объект не может иметь никаких параметров времени жизни (кроме static
), или сам объект также должен учитывать это время жизни, что в общем случае невозможно. Чтобы исправить это:
pub fn add<T: MiddlewareHandler 'static> (amp;mut self, handler: T) {
self.handlers.push(box handler);
}
Читается немного странно, но в нем говорится: « T
необходимо реализовать MiddlewareHandler
, и он не может содержать никаких ссылок, у которых нет времени static
жизни». Это работает только для static
.
Комментарии:
1. Я думаю, что я добавил
' static
почти все места в этом фрагменте, но я, очевидно, пропустил попытку'static
там 😉 Но я не понимаю, почему это там не нужно: github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67 Чем отличается их реализация в этом отношении?2. Поскольку признак наследуется от
Send
иSend
подразумевает'static
3. Черт возьми! Я просмотрел документацию
Send
, но это не вызвало никаких вопросов, потому что я не создаю здесь никаких задач, поэтому это казалось излишним. Возможно, вы можете ответить на два дополнительных вопроса:pub trait MiddlewareHandler: Clone Send
работает, но странно «злоупотреблять»Send
этим. Почему я не могу использоватьpub trait MiddlewareHandler: Clone 'static
then? Вы сказалиSend
, что подразумевает'static
, но я посмотрел на источник doc.rust-lang.org/core/kinds/trait.Send.html и не могу найти никаких намеков на это. Я бы ожидал увидеть'static
где-нибудь там.4.Типы немного странные, они прямо сейчас встроены в язык (хотя есть RFC, чтобы изменить это). Я ожидал
Clone 'static
бы, что сработает, мне грустно, что это не так.5. Тогда хорошо. Было бы правильно вывести из
send
, если вы действительно просто хотите сделать свой тип статическим atm? Я хочу написать идиоматический Rust, и вывод изsend
него кажется ненужным, учитывая его описание. Не могли бы вы сделать то же самое здесь с текущим дизайном Rust?
Ответ №2:
Объект признака стирает тип внутренних данных, что означает, что он не известен, просто взглянув на объект Box<Trait>
признака. В частности, любое время жизни данных также стирается, поэтому компилятор не может определить, содержит ли / когда объект признака ссылки на недопустимые данные (т. Е. Время жизни некоторой ссылки истекло), Поэтому Rust в настоящее время обеспечивает, чтобы любые данные в принадлежащем объекту признака никогда не должны «истекать». То есть в нем нет ссылок (ну, если быть точным, любые ссылки действительны вечно, т.Е. 'static
).
Это выражается через встроенную «черту» 'static
:
pub fn add<T: 'static MiddlewareHandler>(...
(Это может измениться в будущем, поскольку принадлежащие объекты признаков могут быть ограничены реальным временем жизни, и поэтому хранение без 'static
ссылок будет безопасным.)
Комментарии:
1. Отличный ответ! Спасибо за это. Я все еще удивляюсь, почему это работает для них: github.com/iron/iron/blob/master/src/chain/stackchain.rs#L67 Я не понимаю, чем их код отличается от моего. Кроме того, если я изменю код таким образом, я столкнусь со следующей ошибкой
instantiating a type parameter with an incompatible type T, which does not fulfill 'static
, так что, похоже, это указывает на то, что у меня ошибка где-то еще, может быть? : -S