2016-11-12 4 views
2

Когда я пытаюсь скомпилировать этот код (playground):Займитесь закрытия фильтра, не живут достаточно долго

fn main() { 
    let iter = "abc123".chars().filter(&|&c: &char| c.is_digit(10)); 
    match iter.clone().take(3).count() { 
     3 => println!("{}", iter.collect::<String>()), 
     _ => {} 
    } 
} 

Я получаю следующее сообщение об ошибке:

error: borrowed value does not live long enough 
--> test.rs:2:41 
    | 
2 |  let iter = "abc123".chars().filter(&|c: &char| c.is_digit(10)); 
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here 
    |           | 
    |           temporary value created here 
... 
7 | } 
    | - temporary value needs to live until here 
    | 
    = note: consider using a `let` binding to increase its lifetime 

Я понимаю, что ошибка услужливо говоря, что я объявляю закрытие в строке выше с let f = &|c: &char| c.is_digit(10); (working code), но почему именно это необходимо?

Я также не знаю, почему закрытие должно содержать две ссылки - &|c: &char|. Не "abc123".chars() просто создать итератор символов?

+0

Релевантно: http://stackoverflow.com/q/31374051/155423; около дубликатов: http://stackoverflow.com/q/28776630/155423, http://stackoverflow.com/q/23969191/155423, [рабочий код] (http://play.integer32.com/?gist=feb39ad6c2bd1641dcf463b65d560986&version = стабильный); TL; DR: вы, вероятно, хотите использовать 'by_ref'. – Shepmaster

+0

@Shepmaster Я предполагаю, что я пытался спросить, как клонировать Iterator (до того, как я запутался в сообщении об ошибке). Итак, как бы я это сделал (https://play.rust-lang.org/?gist=a8f4f33423f100f857ffe2ce4f0263a8&version=stable&backtrace=0) например (я знаю, что это не лучший способ сделать это). – gib

ответ

5

but why exactly is this necessary?

Я не знаю, как объяснить это гораздо лучше, чем сообщения об ошибках:

temporary value only lives until here 
temporary value created here 

Вы создаете временное значение (само закрытие) в заявлении, а затем принимает ссылку к нему. Когда оператор заканчивается, значение уничтожается - ничто не владеет им! Проблема в том, что код пытается сохранить ссылку на теперь уничтоженное значение. Если компилятор разрешил это, тогда, когда он пошел использовать эту ссылку, кто знает, к каким случайным данным будет доступен доступ.

the closure has to contain two references

Ну, это не имеют к. filter(|c| c.is_digit(10)) работает нормально; вывода типа c будет автоматически набираться как &char. &c только шаблон соответствует и автоматически разыгрывает значение. Это избыточно, потому что метод вызывает automatically dereference.

Большая проблема в том, что код пытается клонировать итератор, содержащий замыкание, которое вы не можете сделать (1, 2, 3, 4 (благость, люди отказываются искать, прежде чем задавать вопросы)). Умный способ, которым вы решили обойти это, - это клонирование ссылки на закрытие, что хорошо.

Проблема сводится к тому, чтобы ссылаться на то, что было уничтожено в конце инструкции.


Если цель состоит в том, чтобы игнорировать все не-цифры, пропустить первые 3 цифры, а затем собрать остальные цифры, вы можете использовать Iterator::skip:

let iter = "abc123".chars().filter(|c| c.is_digit(10)); 
let together: String = iter.skip(3).collect(); 
println!("{}", together); 

Если цель состоит в том, чтобы принимать только первые 3 цифры тогда и только тогда, когда их было три цифры, тогда я мог бы всегда собирать эти цифры и проверять, был ли это конец:

let mut iter = "abc123".chars().filter(|c| c.is_digit(10)); 
let together: String = iter.by_ref().take(3).collect(); 

if iter.next().is_none() { 
    println!("{}", together); 
} 

Используется Iterator::by_ref. Вместо , потребляющего, итератор, by_ref создает изменяемую ссылку на него.Обменяемые ссылки на итераторы также реализовать Iterator, поэтому звонки take и collect работают нормально. Однако, когда это делается, iter остается в силе.

+0

Да, извините, из-за того, что я изначально имел что-то вроде [this] (https://play.rust-lang.org/?gist=080f87f21823940bb52e92bc55a1299c&version=stable&backtrace=0), но потом я закончил с '& | c : & char | 'пытается успокоить компилятор. Это только я пытаюсь добраться до MCVE, я знаю, что это не лучший способ сделать это. Это действительно просветитель! – gib

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

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