args
— это Vec<String>
, а итератор iter
возвращает ссылки на строки (&String
). Один из способов увидеть типы — попытаться присвоить значение типу единицы измерения ()
:
let () = args.iter().next();
У которого есть ошибка, которая показывает тип:
error[E0308]: mismatched types
--> src/main.rs:5:13
|
5 | let () = args.iter().next();
| ^^ expected enum `std::option::Option`, found ()
|
= note: expected type `std::option::Option<&std::string::String>`
= note: found type `()`
В своем закрытии вы пытаетесь автоматически разыменовать (|a, &b|
) второе значение. Если бы вы были разыменованы, то String
был бы перемещен из вектора, что оставило бы память в векторе в неопределенном состоянии! Если бы мы попытались использовать вектор после этого, мы могли бы вызвать segfault, одну из вещей, которую Rust призван предотвратить.
Проще всего вообще не разыменовывать его (оставив b
как &String
):
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let sum_args: i32 =
args
.iter()
.skip(1)
.fold(0, |a, b| a + b.parse::<i32>().expect("Not an i32!"));
println!("{:?}", sum_args.to_string());
}
Некоторые дополнительные мелкие моменты...
Вам не нужно указывать тип векторных элементов, когда вы collect
:
let args: Vec<_> = env::args().collect();
Вам не нужно создавать строку для вывода числа:
println!("{}", sum_args);
И я бы, вероятно, написал это как
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let sum_args: i32 =
args
.iter()
.skip(1)
.map(|n| n.parse::<i32>().expect("Not an i32!"))
.sum();
println!("{}", sum_args);
}
Предупреждение о чрезмерно умном решении
Если вам нужно суммировать кучу итераторов потенциально ошибочных чисел, вы можете создать тип, который реализует FromIterator
и не выделяет никакой памяти:
use std::env;
use std::iter::{FromIterator, Sum};
struct SumCollector<T>(T);
impl<T> FromIterator<T> for SumCollector<T>
where T: Sum
{
fn from_iter<I>(iter: I) -> Self
where I: IntoIterator<Item = T>
{
SumCollector(iter.into_iter().sum())
}
}
fn main() {
let sum: Result<SumCollector<i32>, _> = env::args().skip(1).map(|v| v.parse()).collect();
let sum = sum.expect("Something was not an i32!");
println!("{}", sum.0);
}
Rust 1.16 должен даже поддерживать это из коробки:
use std::env;
fn main() {
let sum: Result<_, _> = env::args().skip(1).map(|v| v.parse::<i32>()).sum();
let sum: i32 = sum.expect("Something was not an i32!");
println!("{}", sum);
}
person
Shepmaster
schedule
09.04.2015