Code Fix

中級

ブロック内でのシャドーイングは外側の変数に反映されない

if文などのブロックの中でletを使って同じ名前の変数を再宣言(シャドーイング)すると、それはブロック内だけで有効な別の変数になります。ブロックを抜けると、外側の変数は変更されないまま残ります。

なぜエラーが出ないのか

出力: inside: 120
(エラーなし)
Rustは何も報告しません。型としても借用としても正しいコードだからです
出力: inside: 120
実際の出力 — 期待した結果と食い違っている箇所
見つけ方
エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます

このエラーが出る典型パターン

パターン1

 1  fn main() {
 2      let mut total = 100;
 3      let bonus = 20;
 4      if bonus > 0 {
 5          let total =     total + bonus;
                   ^
 6          println!("inside: {}", total);
 7      }
 8      println!("outside: {}", total);
 9  }
出力: inside: 120 outside: 100

letによる再宣言はブロック内だけで有効な新しい変数を作ります。外側のtotalを更新したいなら代入(=)を使います。

直し方: let total =total = にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  fn main() {
 2      let mut balance = 500;
 3      let deposit = 100;
 4      if deposit > 0 {
 5          let balance =     balance + deposit;
                    ^
 6          println!("inside: {}", balance);
 7      }
 8      println!("outside: {}", balance);
 9  }
出力: inside: 600 outside: 500

letで作った変数はブロックを抜けると消え、外側の変数には一切影響しません。

直し方: let balance =balance = にします。

この問題を解いてみる →

パターン3

 1  fn main() {
 2      let mut level = 1;
 3      let gained = 2;
 4      if gained > 0 {
 5          let level =     level + gained;
                   ^
 6          println!("inside: {}", level);
 7      }
 8      println!("outside: {}", level);
 9  }
出力: inside: 3 outside: 1

シャドーイングと再代入は見た目が似ていますが、変数のスコープに与える影響が全く違います。

直し方: let level =level = にします。

この問題を解いてみる →

パターン4

 1  fn main() {
 2      let mut stock = 30;
 3      let arrived = 10;
 4      if arrived > 0 {
 5          let stock =     stock + arrived;
                   ^
 6          println!("inside: {}", stock);
 7      }
 8      println!("outside: {}", stock);
 9  }
出力: inside: 40 outside: 30

ブロックの外にも反映させたい更新は、シャドーイングではなくmut変数への代入で行う必要があります。

直し方: let stock =stock = にします。

この問題を解いてみる →

パターン5

 1  fn main() {
 2      let mut hp = 50;
 3      let heal = 15;
 4      if heal > 0 {
 5          let hp =     hp + heal;
                  ^
 6          println!("inside: {}", hp);
 7      }
 8      println!("outside: {}", hp);
 9  }
出力: inside: 65 outside: 50

letを付けた瞬間に、それはまったく別の変数として扱われ、外側の変数とは無関係になります。

直し方: let hp =hp = にします。

この問題を解いてみる →

よくある誤解

「同じ名前でletし直せば、外側の変数もその値に更新されるはず」という思い込みは誤りです。letによるシャドーイングは常に新しい変数を作る操作であり、既存の変数への代入(mut変数への=での再代入)とは別物です。

まとめ

ブロック内でのシャドーイングは外側の変数に反映されないは中級でつまずきやすい項目です。上の5パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)