Создать замыкание, возвращающее итератор по строке - PullRequest
0 голосов
/ 23 июня 2019

Я хочу написать замыкание, которое принимает объект и возвращает из него итератор. Идея состоит в том, чтобы хранить замыкание в структуре и применять по мере необходимости:

fn main() {
    let iter_wrap = |x: &String| Box::new(x.chars());
    let test = String::from("test");

    for x in iter_wrap(&test) {
        println!("{}", x);
    }
}

Это вызывает ошибку:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
 --> src/main.rs:2:45
  |
2 |     let iter_wrap = |x: &String| Box::new(x.chars());
  |                                             ^^^^^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 2:21...
 --> src/main.rs:2:21
  |
2 |     let iter_wrap = |x: &String| Box::new(x.chars());
  |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
 --> src/main.rs:2:43
  |
2 |     let iter_wrap = |x: &String| Box::new(x.chars());
  |                                           ^
note: but, the lifetime must be valid for the call at 5:14...
 --> src/main.rs:5:14
  |
5 |     for x in iter_wrap(&test) {
  |              ^^^^^^^^^^^^^^^^
note: ...so that argument is valid for the call
 --> src/main.rs:5:14
  |
5 |     for x in iter_wrap(&test) {
  |              ^^^^^^^^^^^^^^^^

Я пытался изменить String на Vec и удалить бокс, но результат тот же.

Как я могу заставить его скомпилироваться?

Ответы [ 3 ]

2 голосов
/ 23 июня 2019

Закрытия с заимствованиями в параметрах или типах возврата имеют некоторые известные ошибки, как показано в этом отчете о проблемах, а также другие, на которые оно ссылается: https://github.com/rust-lang/rust/issues/58052

Есть несколько способов обойти эту проблему.

Использование полностью определенного синтаксиса

fn main() {
    let iter_wrap = |x| Box::new(str::chars(x));
    let test = String::from("test");

    for x in iter_wrap(&test) {
        println!("{}", x);
    }
}

Использование аннотации типа в корпусе крышки

fn main() {
    let iter_wrap = |x| {let x: &String = x; Box::new(x.chars()) };
    let test = String::from("test");

    for x in iter_wrap(&test) {
        println!("{}", x);
    }
}
1 голос
/ 23 июня 2019

Я не совсем уверен, чего вы пытаетесь достичь, но, в основном, просто взглянув на предоставленный вами пример, вам не нужно замыкание, а функция:

use std::str::Chars;

fn main() {
    fn iter_wrap(s: &str) -> Chars {
        s.chars()
    }

    let test = "test".to_string();

    for c in iter_wrap(&test) {
        println!("{}", c);
    }
}

Или у вас может быть замыкание, то есть , охватывающее внешний мир, в данном случае, вашу строку:

fn main() {
    let test = "test".to_string();
    let iter_wrap = || test.chars();

    for c in iter_wrap() {
        println!("{}", c);
    }
}
0 голосов
/ 24 июня 2019

Вам необходимо определить и использовать время жизни, которое меньше времени жизни самой функции. Я попробовал это, и это сработало:

fn foo<'a, 'b: 'a>() {
    let test = String::from("test");
    let iw = |x: &'b String| {
        x.chars()
    };

    for x in iw(&test) {
        println!("{}", x);
    }
}

fn main() {
    foo()
}

Недостаточно просто использовать время жизни 'a, вам нужно время жизни, которое на короче чем это, поэтому 'b: 'a.

Теперь я не могу объяснить, что с определением «a» и «b» использование &'a String в определении замыкания также работает ...

...