2016-10-21 8 views
2

Я пытаюсь сделать цепочечные преобразования по признаку, и у меня возникают некоторые проблемы.Цепочки функций по признаку

У меня есть куча функций преобразования вида:

fn transform<T: MyTrait>(in: T) -> impl MyTrait 

И я хочу, функция chain, которая позволит мне сделать

let mut val: Box<MyTrait> = ...; 
val = chain(val, transform1); 
val = chain(val, transform2); 
... 

Я написал эту функцию

fn chain<T, U, F>(val: Box<T>, f: F) -> Box<MyTrait> 
    where T: MyTrait, 
     U: MyTrait, 
     F: FnOnce(T) -> U { 
    Box::new(f(*val)) 
} 

Но когда я скомпилирую, средство проверки займа сообщает мне, что параметр типа U не живет достаточно долго. Я почти уверен, что мои черты характера - это то, что я хочу, и я пробовал разные вещи со спецификациями жизни, поэтому я застрял :(

PS: Возможно ли создать функцию chain по умолчанию на MyTrait? I не думаю, что это возможно, но мы никогда не знаем ...

EDIT:

Я добавил исправления, предложенные @ CHRIS-Эмерсон в своем ответе, по мере того как я сказал в своем комментарии, я раскрыл еще одну проблему, которая кажется неразрешимой.

Here - это суть кода, чтобы не загромождать этот пост.

Короче говоря, проблема заключается в следующем: функция цепи должна разыменовать Box<T> объекта и передать T к функции преобразования, поэтому T должен быть Sized. Но весь смысл этой функции заключался в том, чтобы разрешить использование произвольных (и неизвестных при компиляции). Например:

let mut val: Box<MyTrait> = ...; 
//here we can know the type inside the Box 
if ... { 
    val = chain(val, transform); 
} 
//but here we don't know anymore 
//(its either the original type, 
//or the type returned by transform) 

Так эта конструкция не может работать, если функция преобразования не может принять & T или & MUT T (который он не может, так как мне нужно потреблять вход для получения выходного сигнала) ,

+2

Я в замешательстве, что 'T' и' U' должны быть разными чертами? – LinearZoetrope

+0

@ Jsor: Вероятно, учитывая, что 'F' является трансформатором здесь. –

+0

@ MatthieuM. Я думаю, что они на самом деле хотят преобразовать две реализации одного и того же признака, а затем преобразовать их в объект с боксами. – LinearZoetrope

ответ

2

Сообщение полный компилятор:

error[E0310]: the parameter type `U` may not live long enough 
--> <anon>:7:3 
    | 
7 | Box::new(f(*val)) 
    | ^^^^^^^^^^^^^^^^^ 
    | 
    = help: consider adding an explicit lifetime bound `U: 'static`... 
    note:...so that the type `U` will meet its required lifetime bounds 
--> <anon>:7:3 
    | 
7 | Box::new(f(*val)) 
    | ^^^^^^^^^^^^^^^^^ 

error: aborting due to previous error 

Компилятор говорит, что ему нужно U жить для 'static жизни; что это действительно означает, что любые ссылки внутри него должны быть действительны для этого времени жизни, так как Box может жить вечно (насколько компилятор знает здесь).

Так исправить просто: добавить 'static в пределах U «s:

fn chain<T, U, F>(val: Box<T>, f: F) -> Box<MyTrait> 
    where T: MyTrait, 
     U: MyTrait + 'static, 
     F: FnOnce(T) -> U, 
{ 
    Box::new(f(*val)) 
} 

добавление дополнительного связанного U: 'static также эквивалентны.

+0

Возможно, «быстрее» сказать «U: MyTrait +» static, а не ввести вторую строку 'U'. –

+0

Да, я подумал об этом, но произвольно решил, что было бы лучше добавить границу с seaprate. Я добавлю примечание. –

+0

Я не думаю, что это яснее, поскольку кажется необычным иметь вторую строку, описывающую параметр типа (и, следовательно, на первый взгляд это может не выглядеть) – Neikos