#rust
#Ржавчина
Вопрос:
Я пытаюсь создать строку, добавив к ней внутри цикла for. По какой-то причине строка перемещается в цикл for, и я не могу заставить ее работать. Я, очевидно, что-то упускаю. Вот короткий фрагмент кода, который демонстрирует это поведение:
fn main() {
let s = format!("some string");
for x in vec!(1,2).move_iter() {
s.append("some other string");
}
}
Я получаю следующую ошибку от компилятора ( rustc 0.11.0-pre (c0a6f72 2014-06-12 14:17:13 0000)
):
test.rs:4:9: 4:10 error: use of moved value: `s`
test.rs:4 s.append("some other string");
^
test.rs:4:9: 4:10 note: `s` moved here because it has type `collections::string::String`, which is non-copyable (perhaps you meant to use clone()?)
test.rs:4 s.append("some other string");
^
error: aborting due to previous error
Ответ №1:
Обновление: в последней версии Rust (начиная с 1.0.0-alpha) append()
метод больше не существует. Однако оба String
Vec
метода and перегружены, и он ведет себя точно так же, как старый append()
:
let s = String::new() "some part" "next part";
Операторы всегда принимают свои операнды по значению, поэтому это не вызывает ненужных перераспределений. Правильный операнд должен быть amp;str
for String
или amp;[T]
for Vec<T>
; в последнем случае T
должно быть Clone
.
В любом случае, push_str()
все еще доступно.
Причина, по которой вы получаете эту ошибку, заключается в том, что вы используете неправильный метод 🙂
String::append()
метод похож на конструктор; предполагается, что он используется следующим образом:
let s = String::new()
.append("some part")
.append("next part");
Фактически, вы сможете использовать его в своем коде:
let mut s = "some string".to_string();
for amp;x in [1, 2].iter() {
s = s.append("some other string"); // note the reassignment
}
Это происходит потому append()
, что имеет эту подпись:
fn append(self, other: amp;str) -> String { ... }
То есть он принимает получателя по значению и перемещается в вызов. Это позволяет легко создавать цепочки, но несколько неудобно, если вам нужно изменить существующую переменную.
Вызывается метод, который вы ищете push_str()
:
let mut s = "some string".to_string();
for amp;x in [1, 2].iter() {
s.push_str("some other string");
}
Он просто добавляет переданный фрагмент строки к существующему String
. Обратите внимание, что вы также должны пометить s
как изменяемый. Вам также не нужно выделять новый вектор с помощью vec!()
, здесь достаточно статического массива.
Тем не менее, лучше полностью избегать мутации, если это возможно. предложение @A.B. использовать fold()
абсолютно правильно.
Комментарии:
1. Спасибо. Пока я использую push_str и посмотрю, смогу ли я преобразовать код в более функциональный стиль, чтобы избежать использования mut позже.
Ответ №2:
Сигнатура функции append
fn append(self, second: amp;str) -> String
self
передается по значению, что означает, что если бы self реализовал свойство копирования, оно было бы скопировано, в противном случае оно было бы перемещено. Строка не реализует копирование, поэтому она будет перемещена.
Операция складывания может удерживать строку между добавлениями:
let s = format!("some string");
let s = vec!(1,2).iter()
.fold(s, |s, num| s.append("some other string"));
println!("{}",s);
Я предполагаю, что в конечном итоге вы хотите прочитать строки из вектора. Если вы просто пытаетесь повторить операцию несколько раз, вам следует использовать range(0, n)
or std::iter::Repeat::new("some other string").take(n)
в качестве итератора для выполнения сворачивания.
Комментарии:
1. Я посмотрю, смогу ли я адаптировать код для использования fold, поскольку это выглядит аккуратнее, чем обычный цикл for .