У меня есть фрагмент кода, который не компилируется:
struct A {
x: [u32; 10],
}
impl A {
fn iter<'a>(&'a self) -> impl Iterator<Item = u32> + 'a {
(0..10).map(|i| self.x[i])
}
}
fn main() {}
Компилятор говорит:
error[E0373]: closure may outlive the current function, but it borrows `self`, which is owned by the current function
--> src/main.rs:7:21
|
7 | (0..10).map(|i| self.x[i])
| ^^^ ---- `self` is borrowed here
| |
| may outlive borrowed value `self`
help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword
|
7 | (0..10).map(move |i| self.x[i])
| ^^^^^^^^
Что мне делать, чтобы это работало? Мне понадобится self
позже, поэтому я не могу переместить его, как предлагает компилятор.
Редактировать: Я полагал, что move
создаст проблемы при использовании self
позже. Например, посмотрите код:
struct A {
x: [u32; 3],
}
impl A {
fn iter<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
(0..3).filter(move |&i| self.x[i] != 0).map(move |i| self.x[i])
}
}
fn main() {
let a = A { x : [0, 1, 2]};
for el in a.iter() {
println!("{}", el);
}
}
Здесь &'a self
перемещается дважды, поэтому, по сути, оба закрытия перешли во владение &'a self
. Код действительно компилируется, но я не ожидал, что после перемещения переменную больше нельзя будет использовать. В книге (соответствующий раздел) также приводится пример, подтверждающий мое понимание:
fn main() {
let x = vec![1, 2, 3];
let equal_to_x = move |z| z == x;
println!("can't use x here: {:?}", x);
let y = vec![1, 2, 3];
assert!(equal_to_x(y));
}
Этот код не компилируется. Почему мой код итератора работает с move
?
@Shepmaster Извините, я забыл включить бит, в котором перемещение self
в закрытие, как было предложено компилятором, не является вариантом. Мне он понадобится, чтобы использовать его позже, после звонка на iter()
. Пожалуйста, дайте мне знать, если что-то еще не завершено.
Как я уже упоминал, пожалуйста, предоставить код, который демонстрирует случай, когда добавление move
в закрытие не сработает. Мы не можем волшебным образом создать код, имитирующий ваш код, которого мы никогда не видели.
@Shepmaster Я внес некоторые правки в вопрос. Ключевое слово move
действительно работает в моем случае, но я не могу понять, почему.
Это потому, что я просто перемещаю ссылку, которая копируется, а не перемещается?
Пожалуйста, измените свой вопрос, неясно, о чем вы спрашиваете. Удалите ненужный код и четко спросите, в чем проблема.
Вы кардинально изменили свой вопрос, сделав существующие ответы нерелевантными. Это больше не «как мне сделать X», а теперь «почему этот код (который изначально не был опубликован) компилируется». Было бы несправедливо по отношению к людям, которые нашли время ответить на ваш вопрос оригинал, так радикально его изменить. Удалите свои новые вопросы и задайте новый вопрос, касающийся вашего нового вопроса - Как лучше всего задавать дополнительные вопросы? / Стратегии выхода для «вопросов-хамелеонов»
Похоже, компилятор уже говорит вам, что делать:
help: to force the closure to take ownership of `self` (and any other referenced variables), use the `move` keyword
|
7 | (0..10).map(move |i| self.x[i])
| ^^^^^^^^
Ключевое слово move
дает замыканию владение любой захваченной переменной.
Здесь вы захватываете ссылку self
перемещением, а не сам объект. Вы не можете использовать объект, вызывая метод iter
, потому что он принимает ваш объект не по перемещению, а по ссылке. Вы можете по-прежнему использовать свой объект после вызова iter()
на экземпляре.
Извините, я почти предположил, что это очевидно ... но мне понадобится self
позже. Я отредактировал вопрос сейчас.
@Shepmaster: Хорошо, а какая стандартная фраза здесь? Я имею в виду, что это дает дополнительные ограничения на срок службы 'a
из &'a self
.
Это также не накладывает никаких дополнительных ограничений на 'a
. Как вы заявляете, он передает право собственности на self
(типа &'a Self
) закрытию, в отличие от того, чтобы закрытие использовало ссылку на self
(типа &&'a Self
). Последний не живет достаточно долго, так как выходит за рамки в конце функции.
Хорошо, это проясняет ситуацию. По какой-то причине я думал, что замыкания делают копии захваченных переменных для типов Copy
, поэтому причина, по которой пример в вопросе требовал move
, на самом деле становилась для меня непонятной. Видимо я не один такой: github.com/rust-lang/rust/issues/36569
Просмотрите, как создать минимальный воспроизводимый пример, а затем редактировать свой вопрос, чтобы включить его. На основе код, который вы предоставили существующие ответы решают вашу проблему. Попробуйте создать что-то, что воспроизводит вашу ошибку в Ржавчина Детская площадка, или вы можете воспроизвести это в новом проекте Cargo. Также есть Подсказки MCVE, специфичные для ржавчины.