すでにベストアンサーが選ばれていますが、補足させてください。(他の回答に気づかずに回答を途中まで書いてしまった)
エラーとなる理由は他の方が説明されているとおり所有権によるものです。Vec
から1要素だけmove out(所有権を移動)させることはできません。
clone()
は解決方法のひとつですが、元の値(ここではString
)を複製しますので、ある程度の実行時のコストがかかります。可能な限りはベストアンサーの2つ目の方法である借用を使うのがおすすめです。
rust
1fn main() {
2 // Vec<String>型
3 let v = vec!["zero".to_string(), "one".to_string()];
4 // Vecから1要素だけmove out(所有権を移動)させることはできない。
5 // 質問と同じコンパイルエラー(cannot move out of indexed context)になる
6 // let v1 = v[1]; // String型
7
8 // `&`を使って値を借用すれば、値を複製しないで済む(おすすめの方法)
9 let v1_ref = &v[1]; // &String型
10}
借用を使う場合はプログラムを以下のように修正します。
rust
1use std::env;
2
3fn main() {
4 // Vec<String>型
5 let arg = env::args().collect::<Vec<_>>();
6 // &arg[1]は&String型
7 println!("{}", add1(&arg[1]));
8}
9
10// 引数を&str型にする。こうするとコンパイラの型強制というしくみを
11// 使って、引数として&str型の値と、&String型の値の両方を取れるように
12// なるので便利
13fn add1(s: &str) -> i32 {
14 let a = s.parse::<i32>().unwrap();
15 a + 1 // 最後の式の値が返されるのでreturnキーワードは不要
16}
17
18#[test]
19fn test_add1() {
20 let x = "5".to_string(); // String型
21 assert_eq!(add1(&x), 6);
22 let x = "7"; // &str型
23 assert_eq!(add1(x), 8);
24}
その他の方法としてはstd::mem::replace()
を使って、今の値はmove outし、元の場所に代わりの値を入れることもできます。
rust
1fn main() {
2 // ベクタの内容を変更するので`mut`が必要
3 let mut v = vec!["zero".to_string(), "one".to_string()];
4
5 // 今の値をmove outし、元の場所に代わりの値(例:"dummy")を入れる
6 // v1はString型
7 let v1 = std::mem::replace(&mut v[1], "dummy".to_string());
8}
ところでコマンドライン引数を取り出すときは、また別の回答にある nth()
を使うのが一般的です。これにコマンドライン引数のエラー処理なども加えると元のプログラムは以下のようになります。
rust
1use std::env;
2use std::error::Error;
3
4// 注意:main関数からResult型を返すにはRust 1.26.0かそれ以降が必要
5fn main() -> Result<(), Box<Error>> {
6 // String型
7 let arg1 = env::args().nth(1).ok_or("Please specify arg1.")?;
8 // &String → &strへ型強制する
9 println!("{}", add1(&arg1)?);
10 Ok(())
11}
12
13fn add1(s: &str) -> Result<i32, Box<Error>> {
14 let a = s.parse::<i32>()?;
15 Ok(a + 1)
16}
17
18#[test]
19fn test_add1() {
20 let x = "5".to_string(); // String型
21 assert_eq!(add1(&x).unwrap(), 6);
22 let x = "7"; // &str型
23 assert_eq!(add1(x).unwrap(), 8);
24
25 // i32に変換できない文字列を与えるとエラー
26 assert!(add1("abc").is_err());
27}
実行結果
# 正しいコマンドライン引数を与えた
$ cargo run -- 123
124
# 引数を与えなかった
$ cargo run --
Error: StringError("Please specify arg1.")
# 数値に変換できない値を与えた
$ cargo run -- abc
Error: ParseIntError { kind: InvalidDigit }
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。