元のコードですがクロージャを使うための文法が間違っています。その間違いのせいで、コンパイラはそれをクロージャだと認識せずに、|
演算子によるビット和(bit or)演算だと勘違いしています。
元のコードのクロージャ部分
rust
1i | i | {
2 let mut x: i128 = 1;
3 for _ in 0..i {
4 x *= 2;
5 }
6 x
7}
上の式ですと、たとえばi = 2
のときは以下のような計算をします。
i
を2
で置き換える。
rust
12 | 2 | {
2 let mut x: i128 = 1;
3 for _ in 0..2 {
4 x *= 2;
5 }
6 x
7}
↓
↓
2進数で表すと
↓
rust
10x010 | 0x010 | 0x100
↓
ビット和を求めると
↓
正しい使い方は、まずクロージャを定義して変数から束縛します。
rust
1let power_of_two = |i| {
2 let mut x: i128 = 1;
3 for _ in 0..i {
4 x *= 2;
5 }
6 x
7};
そして定義したクロージャを使います。
rust
1power_of_two(i); // i = 2 なら4が返る
これを元のコードに当てはめると、以下のようになります。
rust
1fn main() {
2 let mut v: Vec<i128> = Vec::new();
3
4 let power_of_two = |i| {
5 let mut x: i128 = 1;
6 for _ in 0..i {
7 x *= 2;
8 }
9 x
10 };
11
12 for i in 0..10 {
13 v.push(power_of_two(i));
14 }
15
16 for i in v {
17 println!("{}", i);
18 }
19}
これで正しい答えが得られます。
実行結果
console
11
22
34
48
516
632
764
8128
9256
10512
追記
余談になりますがイテレータのmap()
とcollect()
を使うと、2つ目のfor
が簡潔に書けます。
rust
1fn main() {
2 let power_of_two = |i| {
3 let mut x: i128 = 1;
4 for _ in 0..i {
5 x *= 2;
6 }
7 x
8 };
9
10 let v = (0..10).map(power_of_two).collect::<Vec<i128>>();
11
12 for i in v {
13 println!("{}", i);
14 }
15}
さらに1つ目のfor
もfold()
で置き換えられます。
rust
1fn main() {
2 let power_of_two = |i| (0..i).fold(1, |x, _| x * 2);
3 let v = (0..10).map(power_of_two).collect::<Vec<i128>>();
4
5 for i in v {
6 println!("{}", i);
7 }
8}
Rustに慣れてきたら、こういう書き方にも挑戦してみてください。
あとi128
型ですが、64ビットのCPUでは直接計算できず、ソフトウェアで計算することになりますので計算が遅いです。もし可能ならCPUが直接計算できるi64
やu64
などを使うのがおすすめです。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/12/27 11:39