#rust
#Ржавчина
Вопрос:
Возможно, это глупый вопрос, но это сводит меня с ума. У меня есть этот простой код:
let args = env::args();
println!("num args read: {}", args.len());
for element in args {
println!("{}", element);
}
let arg_string: String = args.collect();
Это не работает и выдает ошибку:
|
4 | let args = env::args();
| -------- move occurs because `args` has type `std::env::Args`, which does not implement the `Copy` trait
...
8 | for element in args {
| ----
| |
| `args` moved due to this implicit call to `.into_iter()`
| help: consider borrowing to avoid moving into the for loop: `amp;args`
...
14 | let arg_string: String = args.collect();
| ^^^^ value used here after move
Это имеет смысл, поскольку into_iter()
вызов потребляет self
. Итак, я пытаюсь изменить цикл for на for element in amp;args
и получаю эту ошибку:
9 | for element in amp;args {
| -^^^^
| |
| `amp;std::env::Args` is not an iterator
| help: consider removing the leading `amp;`-reference
|
= help: the trait `std::iter::Iterator` is not implemented for `amp;std::env::Args`
= note: `std::iter::Iterator` is implemented for `amp;mut std::env::Args`, but not for `amp;std::env::Args`
= note: required by `std::iter::IntoIterator::into_iter`
Почему я не могу выполнить итерацию по ссылке через итератор? Я обнаружил, что могу сделать
let mut args = env::args();
println!("num args read: {}", args.len());
for element in amp;mut args {
println!("{}", element);
}
let arg_string: String = args.collect();
и это избавляет от ошибки компилятора. Почему я должен использовать изменяемую ссылку здесь, а не просто ссылку?
Комментарии:
1. Вы получаете принадлежащие
String
s по требованию от итератора, но я на самом деле не знаю, почему их не может бытьamp;'static str
.2. Сначала подумайте о создании Vec
let args: Vec<_> = env::args().collect();
. Как упоминалось @kmdreko,env::args()
возвращает итератор, который должен сохранять некоторые изменяемые внутренние указатели при выполнении цикла for.3. FWIW, причиной (ну, одной из причин)
Args
является итератор вместо массиваamp;'static str
, потому что разные платформы имеют разные способы доступа к аргументам. Не все из них обязательно дают неизменяемые указатели на строки в кодировке UTF-8 в статической памяти.Args
Интерфейс настолько общий, насколько это возможно.4. @trentcl Я действительно думаю, что ни одна обычная ОС не гарантирует, что аргументы командной строки являются допустимыми UTF-8. В этом смысле
Args
это определенно не так обобщенно, как может быть, ноArgsOs
есть.
Ответ №1:
Вы используете Args
, как будто это коллекция, но это не так; это итератор. Ваш amp;mut
обходной путь удовлетворяет компилятору, но на самом деле не делает то, что вы хотите. Цикл for исчерпает итератор, что означает args.collect()
, что он не даст никаких значений.
Исправление заключается в вызове env::args()
отдельно для каждого использования. Вы ничего не сохраняете, пытаясь использовать ту же переменную.Я забыл, что Args
это создает принадлежащие String
s, поэтому вам может быть лучше собрать аргументы в Vec
первый, если вам нужно повторить его несколько раз.
Комментарии:
1. Я понимаю ваш комментарий, но я все еще не понимаю, почему я не могу выполнить цикл
amp;args
. В комментарии говорится, чтоargs
это итератор, но означает ли это, что вы не можете выполнять итерации по заимствованным итераторам?2. В принципе. Итерация требует
next()
повторного вызова итератора, который изменяет его. Итак, чтобы выполнить итерацию с помощью заимствованного итератора, вам понадобится новый итератор. Вы могли бы получить новый итератор черезclone()
, но цикл for не сделает это за вас … и в данном случае это даже не вариант, потомуArgs
что не реализуетClone
.