#rust
Вопрос:
У меня возникли проблемы с определением того, какой параметр времени жизни будет работать для этого, поэтому мои текущие обходные пути включают трансмутации или необработанные указатели. У меня есть структура, содержащая указатель на функцию с общим параметром в качестве параметра:
struct CB<Data> {
cb: fn(Data) -> usize
}
Я хотел бы сохранить экземпляр этого, параметризованный каким-либо типом, содержащим ссылку, в какой-либо другой структуре, которая реализует признак с помощью одного метода, и использовать этот метод признака для вызова указателя функции в CB.
struct Holder<'a> {
c: CB<Option<amp;'a usize>>
}
trait Exec {
fn exec(amp;self, v: amp;usize) -> usize;
}
impl<'a> Holder<'a> {
fn exec_aux(amp;self, v: amp;'a usize) -> usize {
(self.c.cb)(Some(v))
}
}
impl<'a> Exec for Holder<'a> {
fn exec(amp;self, v: amp;usize) -> usize
{
self.exec_aux(v)
}
}
Это дает мне пожизненную ошибку для включения «Exec» держателя:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
Простой вызов exec_aux
работает нормально, пока я не определяю это Exec
значение:
fn main() {
let h = Holder { c: CB{cb:cbf}};
let v = 12;
println!("{}", h.exec_aux(amp;v));
}
Кроме того, то, что CB не является универсальным, также делает эту работу:
struct CB {
cb: fn(Option<amp;usize>) -> usize
}
Параметр в моем фактическом коде-это не usize
что-то большое, что я бы предпочел не копировать.
Ответ №1:
Продолжительность жизни в вашей Exec
черте неявно такова:
trait Exec {
fn exec<'s, 'a>(amp;'s self, v: amp;'a usize) -> usize;
}
Другими словами, типы, которые реализуют Exec
, должны принимать любые периоды жизни 's
и 'a
. Однако ваш Holder::exec_aux
метод ожидает определенного времени жизни 'a
, связанного с параметром времени жизни Holder
типа.
Чтобы это сработало, вам нужно вместо этого добавить в 'a
качестве параметра срок Exec
службы признак, чтобы вы могли реализовать признак специально для этого срока службы:
trait Exec<'a> {
// ^^^^ vv
fn exec(amp;self, v: amp;'a usize) -> usize;
}
impl<'a> Exec<'a> for Holder<'a> {
// ^^^^ vv
fn exec(amp;self, v: amp;'a usize) -> usize
{
self.exec_aux(v)
}
}
Комментарии:
1. Спасибо. Так будет ли считаться дурным тоном, скажем, в библиотеке/ящике, делать эти неявные периоды жизни явными для новых черт, даже если я не уверен, что они будут реализованы для чего-то подобного?
Ответ №2:
Проблема здесь в том, что Exec
признак слишком общий, чтобы его можно было использовать таким образом Holder
. Во-первых, рассмотрим определение:
trait Exec {
fn exec(amp;self, v: amp;usize) -> usize;
}
Это определение приведет к тому, что компилятор автоматически назначит два анонимных срока службы для amp;self
и amp;v
в exec
. Это в основном то же самое, что
fn exec<'a, 'b>(amp;'a self, v: amp;'b usize) -> usize;
Обратите внимание, что нет никаких ограничений на то, кто кого должен пережить, ссылки просто должны быть живыми во время вызова метода.
Теперь рассмотрим определение
impl<'a> Holder<'a> {
fn exec_aux(amp;self, v: amp;'a usize) -> usize {
// ... doesn't matter
}
}
Поскольку мы знаем, что amp;self
это a amp;Holder<'a>
(это то, к чему impl
относится), нам нужно иметь по крайней мере a amp;'a Holder<'a>
здесь, потому amp;'_ self
что не может быть жизни короче, чем 'a
в Holder<'a>
. Таким образом, это говорит о том, что два параметра имеют одинаковый срок службы: amp;'a self, amp;'a usize
.
Где все идет не так, как надо, так это когда вы пытаетесь совместить то и другое. Эта черта вынуждает вас использовать следующую подпись, которая (опять же) имеет два различных неявных периода жизни. Но фактический Holder
, для которого вы затем пытаетесь вызвать метод, заставляет вас иметь одинаковое время жизни для amp;self
и amp;v
.
fn exec(amp;self, v: amp;usize) -> usize {
// Holder<'a> needs `v` to be `'a` when calling exec_aux
// But the trait doesn't say so.
self.exec_aux(v)
}
Одним из решений является переопределение признака как
trait Exec<'a> {
fn exec(amp;'a self, v: amp;'a usize) -> usize;
}
а затем реализовать его как
impl<'a> Exec<'a> for Holder<'a> {
fn exec(amp;'a self, v: amp;'a usize) -> usize {
self.exec_aux(v)
}
}