Многие языки выбирают способ назначения присваивания вместо выражения, включая Python:
foo = 42 # works
if foo = 42: print "hi" # dies
bar(foo = 42) # keyword arg
и Голанг:
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 с помощью явного синтаксиса объявления и другого синтаксиса именованных аргументов). Но это нормально, чтобы запретить их, так как есть много других вариантов того же эффекта.
Код без ошибок важнее краткого кода.