2016-10-01 1 views
2

У меня есть-структуру, которая выглядит примерно так:Как клонировать закрытие, чтобы их типы были одинаковыми?

pub struct MyStruct<F> where F: Fn(usize) -> f64 { 
    field: usize, 
    mapper: F, 
    // fields omitted 
} 

Как реализовать Clone для этой структуры?

Один способ я нашел, с помощью которого я могу скопировать тело функции:

let mapper = |x| (mystruct.mapper)(x); 

Но это приводит к mapper имеющих различный тип, чем у mystruct.mapper.

playpen link

+0

Что такое 'I'? Это не компилируется. Если 'F' ничего не вернул, почему бы не просто' # [getive (Clone)]? – ljedrz

+0

@ljedrz Ах! Извините, исправил его ... Пожалуйста, взгляните на ссылку в манере, которую я добавил сейчас. – John

ответ

3

Вы не можете Clone закрытия. Единственным, кто в состоянии реализовать Clone для закрытия, является компилятор ... и он не. Итак, вы вид застрял.

Существует один способ обойти это, хотя: если у вас есть замыкание с не захваченных переменными, вы можете заставить копию с помощью unsafe кода. Тем не менее, более простой подход на заключается в том, что указывает на то, что вместо, так как у них нет захваченной среды (любое закрытие нулевого размера может быть переписано как функция) и Copy.

+0

Спасибо! Теперь, когда я думаю об этом, мне не нужно будет фиксировать переменные в закрытии, хотя было бы лучше (более читаемо) использовать закрытие. Любая идея, почему «Clone» не реализован для закрытия в компиляторе? – John

+1

@ John Я считаю, что часть проблемы заключается в том, что для реализации «Clone» компилятор должен знать, что такое «Clone». Исторически это не так. Кроме того, как насчет других черт? Если закрытие также будет «Копировать»? 'Eq'? Где вы проводите линию? Я не думаю, что кто-то действительно уверен, что именно *, нужно сделать здесь. –

+2

'fn (usize) -> f64' (« тип fn ») не имеет нулевого размера, это эквивалент указателя на функцию.'fn (usize) -> f64 {:: some :: specific :: function}' («тип элемента fn») имеет нулевой размер, но вы не можете записать этот тип, поэтому единственный способ, которым вы можете воспользоваться из этого является принятие универсального типа 'F: Fn (u64) -> f64 + Copy' (т. е. просто добавьте' Copy', связанную с кодом в вопросе). – delnan

0

Вы можете использовать trait objects, чтобы быть в состоянии осуществить Сlone для структуры:

use std::rc::Rc; 

#[derive(Clone)] 
pub struct MyStructRef<'f> { 
    field: usize, 
    mapper: &'f Fn(usize) -> f64, 
} 


#[derive(Clone)] 
pub struct MyStructRc { 
    field: usize, 
    mapper: Rc<Fn(usize) -> f64>, 
} 

fn main() { 
    //ref 
    let closure = |x| x as f64; 
    let f = MyStructRef { field: 34, mapper: &closure }; 
    let g = f.clone(); 
    println!("{}", (f.mapper)(3)); 
    println!("{}", (g.mapper)(3)); 

    //Rc 
    let rcf = MyStructRc { field: 34, mapper: Rc::new(|x| x as f64 * 2.0) }; 
    let rcg = rcf.clone(); 
    println!("{}", (rcf.mapper)(3)); 
    println!("{}", (rcg.mapper)(3));  
} 
+0

Да, хотя это допустимый вариант, я хотел избежать динамической отправки. Я пишу симулятор, поэтому я хочу дать компилятору все возможности встраивания замыканий ... – John

+0

Я думаю, что в этом случае встраивание невозможно. Хотя обычный вызов функции (как предложено @DK.) Дешевле, чем вызов объекта-объекта – aSpex

2

Вы можете использовать Rc получить несколько ручек одного и того же unclonable значения (или Arc!). Хорошо работает с закрытием Fn (вызываемый через общие ссылки).

pub struct MyStruct<F> where F: Fn(usize) -> f64 { 
    field: usize, 
    mapper: Rc<F>, 
    // fields omitted 
} 

impl<F> Clone for MyStruct<F> 
    where F: Fn(usize) -> f64, 
{ 
    fn clone(&self) -> Self { 
     MyStruct { 
      field: self.field, 
      mapper: self.mapper.clone(), 
      ... 
     } 
    } 
} 

Помните, что #[derive(Clone)] очень полезный рецепт Clone, но его рецепт не всегда делает то, что нужно для ситуации; это один такой случай.

+0

Помимо ссылки на счетную часть, это так же хорошо, как «сырое» закрытие? Будет ли тело функции встраиваться? (Я предполагаю, что он встроен в «сырые» закрытия, хотя я не уверен в необходимых условиях для этого.) – John

+0

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

Смежные вопросы