2015-02-27 4 views
1

Это может быть дубликат. Я не знаю. Я не мог понять другие ответы достаточно хорошо, чтобы это знать. :)Конфликтный срок службы для итератора, возвращаемого функцией

версия

Ржавчина: rustc 1.0.0-еженощно (b47aebe3f 2015-02-26) (встроенный 2015-02-27)

В принципе, я передаю логическое значение этой функции, которая, как предполагается построить итератор, который фильтрует один путь для истинного и другого способа для false. Тогда это своего рода крэпс, потому что он не знает, как сохранить это логическое значение удобным, я думаю. Я не знаю. Здесь есть несколько проблем с продолжительностью жизни, что обескураживает, потому что это действительно общий шаблон для меня, так как я родом из .NET.

fn main() { 
    for n in values(true) { 
     println!("{}", n); 
    } 
} 

fn values(even: bool) -> Box<Iterator<Item=usize>> { 
    Box::new([3usize, 4, 2, 1].iter() 
     .map(|n| n * 2) 
     .filter(|n| if even { 
      n % 2 == 0 
     } else { 
      true 
     })) 
} 

Есть ли способ сделать эту работу?

+0

Этот вопрос был кросс-размещен на [Rust Reddit] (http://www.reddit.com/r/rust/comments/2xearb/returning_an_iterator/). – Shepmaster

+1

В качестве побочного примечания, используя не зависящие от платформы целые числа, такие как 'usize', когда это не необходимо, используйте' i32' или 'u32'. – heinrich5991

ответ

2

У вас есть две противоречащие друг другу вопросы, так пусть ломаются несколько представительных частей:

[3usize, 4, 2, 1].iter() 
    .map(|n| n * 2) 
    .filter(|n| n % 2 == 0)) 

Здесь мы создаем массив в кадре стека метода, а затем получить итератор к нему. Поскольку нам не разрешено использовать массив, элемент итератора - &usize. Затем мы сопоставляем &usize с номером usize. Затем мы фильтруем на &usize - нам не разрешено использовать отфильтрованный элемент, иначе итератору не придется возвращать его!

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

Чтобы обойти это сейчас, давайте просто сделаем его статичным. Теперь мы можем сосредоточиться на проблеме с even.

filter занимает закрытие. Закрытие захватывает любую используемую переменную, которая не предоставляется в качестве аргумента для закрытия. По умолчанию эти переменные захватываются по ссылке. Однако even снова является переменной, расположенной на стеке стека. Однако на этот раз мы можем отдать его закрытию, используя ключевое слово move. Вот все, вместе взятые:

fn main() { 
    for n in values(true) { 
     println!("{}", n); 
    } 
} 

static ITEMS: [usize; 4] = [3, 4, 2, 1]; 

fn values(even: bool) -> Box<Iterator<Item=usize>> { 
    Box::new(ITEMS.iter() 
     .map(|n| n * 2) 
     .filter(move |n| if even { 
      n % 2 == 0 
     } else { 
      true 
     })) 
} 
+0

Для парней на reddit Rust проблема с [items] также может быть исправлена ​​с использованием vec вместо массива. Я нашел этот вариант предпочтительнее. –

+0

Это, безусловно, сработает, но имеет другую семантику. Если вы используете 'Vec', то значения будут располагаться в куче. Затем вы можете преобразовать 'Vec' в итератор, который будет использовать' Vec', и итератор вернет 'usize' вместо' & usize'. – Shepmaster

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