2014-01-15 2 views
3

Обратите внимание, что этот вопрос относящуюся к версии Руст, прежде чем 1,0 был выпущенВозвращает замыкание из функции

Правильно ли я, что теперь невозможно не вернуться укупорочное из функции, если это понимать был предоставлен функции в своих аргументах? Это очень полезный подход, например, когда мне нужен один и тот же блок кода, параметризованный по-разному, в разных частях программы. В настоящее время компилятор не позволяет что-то вроде этого, естественно:

fn make_adder(i: int) -> |int| -> int { 
    |j| i + j 
} 

Замыкание выделяется в стеке и освобождается после возвращения из функции, поэтому невозможно, чтобы вернуть его.

Можно ли сделать эту работу в будущем? Я слышал, что типы с динамическим размером позволят это.

+0

Хорошо было синтаксис закрытых коробок ... https://github.com/alco/blog/blob/master/posts/2013-07-22-Rust-lambdas.md#boxed-closures, но теперь я не уверен, как сделать то же самое. Похоже, что предоставленное в ответе решение - единственный способ. – Cynede

+0

@ Hewather, да, эти типы затворов были удалены некоторое время до 0,9. –

ответ

3

Это не может работать для закрытия стека; он должен либо не иметь среды, либо иметь свою среду. Предложения DST включают возможность повторного введения типа закрытия с принадлежащей ему среде (~Fn), которая удовлетворит ваши потребности, но пока неясно, произойдет это или нет.

На практике есть другие способы сделать это. Например, вы могли бы сделать это:

pub struct Adder { 
    n: int, 
} 

impl Add<int, int> for Adder { 
    #[inline] 
    fn add(&self, rhs: &int) -> int { 
     self.n + *rhs 
    } 
} 

fn make_adder(i: int) -> Adder { 
    Adder { 
     n: int, 
    } 
} 

Тогда вместо make_adder(3)(4) == 7 было бы make_adder(3) + 4 == 7 или make_adder(3).add(&4) == 7. (Что это Add<int, int>, что она реализуется, а не просто impl Adder { fn add(&self, other: int) -> int { self.n + other } просто, чтобы позволить вам удобство оператора +.)

Это довольно глупый пример, как Adder может точно так же быть во всем int вероятность, но она имеет свои возможности.

Скажем, вы хотите вернуть счетчик; вы можете использовать его как функцию, которая возвращает (0, func), последний элемент является функцией, которая будет возвращать (1, func), & c. Но это может быть лучше моделируется с итератора:

use std::num::{Zero, One}; 

struct Counter<T> { 
    value: T, 
} 

impl<T: Add<T, T> + Zero + One + Clone> Counter<T> { 
    fn new() -> Counter<T> { 
     Counter { value: Zero::zero() } 
    } 
} 

impl<T: Add<T, T> + Zero + One + Clone> Iterator<T> for Counter<T> { 
    #[inline] 
    fn next(&mut self) -> Option<T> { 
     let mut value = self.value.clone(); 
     self.value += One::one(); 
     Some(value) 
    } 

    // Optional, just for a modicum of efficiency in some places 
    #[inline] 
    fn size_hint(&self) -> (uint, Option<uint>) { 
     (uint::max_value, None) 
    } 
} 

Опять же, вы видите, понятие наличия объекта , на котором вы вызываете метод мутировать его состояние и вернуть нужное значение, а не создавать новый отозваны. И так оно и есть: на данный момент, когда вам может понравиться звонить object(), вам необходимо позвонить object.method(). Я уверен, что вы можете жить с такими незначительными неудобствами, которые существуют сейчас.

+0

Благодарим вас за подробное объяснение. Да, структуры - это способ сделать это сейчас (ну, закрытие - это плохие человеческие объекты и наоборот, не так ли? :)), но преимущество возвращающихся закрытий - очень сжатый синтаксис, а семантические или синтаксические накладные расходы дополнительных структур и имплантов. Надежды, принадлежащие нам, скоро вернутся к нам :) –

+0

Что делать, если я хочу иметь функцию, которая возвращает что-то, что я могу передать «карте»? Я не могу всерьез определить новый тип итератора каждый раз в качестве обходного пути. –

+0

@SebastianRedl: извините, но на данный момент новые типы итераторов - единственный способ сделать это. –

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

  • Нет связанных вопросов^_^