"Cannot move out of borrowed content" 总结命令行参数
"Cannot move out of borrowed content" while summing command line arguments
这是我的第一个 Rust 程序,我似乎已经遇到了可怕的借用检查器。 :)
程序应读取命令行中传递的参数,将它们相加并 return 结果。我无法将参数解析为整数。
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>().ok().expect("Not an i32!"));
println!("{:?}", sum_args.to_string());
}
失败:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:9:22
|
9 | .fold(0, |a, &b| a + b.parse::<i32>().ok().expect("Not an i32!"));
| ^-
| ||
| |hint: to prevent move, use `ref b` or `ref mut b`
| cannot move out of borrowed content
我应该如何进行?
args
是一个 Vec<String>
,iter
迭代器 returns 引用字符串 (&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
将被 移出 向量,这会将内存留在矢量处于不确定状态!如果我们在此之后尝试使用向量,我们可能会导致段错误,这是 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);
}
这是我的第一个 Rust 程序,我似乎已经遇到了可怕的借用检查器。 :)
程序应读取命令行中传递的参数,将它们相加并 return 结果。我无法将参数解析为整数。
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>().ok().expect("Not an i32!"));
println!("{:?}", sum_args.to_string());
}
失败:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:9:22
|
9 | .fold(0, |a, &b| a + b.parse::<i32>().ok().expect("Not an i32!"));
| ^-
| ||
| |hint: to prevent move, use `ref b` or `ref mut b`
| cannot move out of borrowed content
我应该如何进行?
args
是一个 Vec<String>
,iter
迭代器 returns 引用字符串 (&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
将被 移出 向量,这会将内存留在矢量处于不确定状态!如果我们在此之后尝试使用向量,我们可能会导致段错误,这是 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);
}