Pythonを含む多くの言語は、代入を式ではなくステートメントにする方法を選択します。
foo = 42 # works
if foo = 42: print "hi" # dies
bar(foo = 42) # keyword arg
およびGolang:
var foo int
foo = 42 # works
if foo = 42 { fmt.Printn("hi") } # dies
他の言語には割り当てはありませんが、OCamlなどのスコープ付きバインディングがあります。
let foo = 42 in
if foo = 42 then
print_string "hi"
ただし、let
式そのものです。
割り当てを許可することの利点は、たとえば次のPerlスニペットのように、条件内の関数の戻り値を直接確認できることです。
if (my $result = some_computation()) {
say "We succeeded, and the result is $result";
}
else {
warn "Failed with $result";
}
Perlはさらに、宣言をその条件のみにスコープするため、非常に便利です。また、新しい変数を宣言せずに条件内で割り当てるif ($foo = $bar)
と警告が表示されますが、警告は表示if (my $foo = $bar)
されますが、表示されません。
通常、別のステートメントで割り当てを行うだけで十分ですが、スコープの問題を引き起こす可能性があります。
my $result = some_computation()
if ($result) {
say "We succeeded, and the result is $result";
}
else {
warn "Failed with $result";
}
# $result is still visible here - eek!
Golangは、エラーチェックの戻り値に大きく依存しています。したがって、条件文で初期化ステートメントを取得できます。
if result, err := some_computation(); err != nil {
fmt.Printf("Failed with %d", result)
}
fmt.Printf("We succeeded, and the result is %d\n", result)
他の言語では、型システムを使用して、条件内で非ブール式を禁止しています。
int foo;
if (foo = bar()) // Java does not like this
もちろん、ブール値を返す関数を使用すると失敗します。
偶発的な割り当てを防ぐためのさまざまなメカニズムを見てきました。
- 式としての割り当てを許可しない
- 静的型チェックを使用する
- 割り当ては存在せず、
let
バインディングしかありません
- 初期化ステートメントを許可し、そうでない場合は割り当てを許可しない
- 宣言なしの条件内での割り当てを許可しない
昇順の優先順位でそれらをランク付けしました-式内の割り当ては便利です(そして、明示的な宣言構文と別の名前付き引数構文を持つことでPythonの問題を簡単に回避できます)。しかし、同じ効果に対する他の多くのオプションがあるので、それらを禁止することは問題ありません。
バグのないコードは簡潔なコードよりも重要です。