История изменений
Исправление freecoder, (текущая версия) :
Вообще новые имена переменных в Rust вводятся только при сопоставлении и в составе образца! Это правило просто и универсально в рамках языка. В первой редакции Rust-book даже не было терминологии «ввести переменную», а говорилось о «связывании имён (name binding)», что было корректнее, но обескураживало новичков.
let x = foo();
Здесь происходит сопоставление с образцом, в результате которого значение выражения, которое вернул вызов foo(), сопоставляется с паттерном слева, состоящим только из одного нового имени x, в результате чего это имя связывается со всем значением.
let Point { x, y: b } = foo();
Здесь уже паттерн сложнее, новое имя x связывается со значением одноимённого поля экземпляра структуры Point, который возвращается вызовом foo(). А новое имя b связывается со значением поля y.
Так как это операция let и сопоставление полное, то введённые имена живут до конца текущего скоупа. Если нужно условное сопоставление, где новые имена будут жить только в новом скоупе (блоке), то можно использовать match или if let:
if let Some(val) = bar() {
println!("Можно использовать имя val = {val}");
}
...
match bar() {
Some(val) => println!("Можно использовать имя val = {val}"),
None => println!("Вызов вернул вариант None"),
}
Так что в Rust новые имена «переменных» могут вводиться только в составе образца в операциях: match, let, let ... else, if let, ... else if let, while let, for, в аргументах функций и замыканий. И больше - нигде. Для цикла for это приводит к довольно элегантным конструкциям:
for i in 0..5 {
println!("Iteration: {i}");
}
for (i, item) in [2, 5, 7].into_iter().enumerate() {
println!("Iteration: {i}, value: {item}");
}
Исправление freecoder, :
Вообще новые имена переменных в Rust вводятся только при сопоставлении и в составе образца! Это правило просто и универсально в рамках языка. В первой редакции Rust-book даже не было терминологии «ввести переменную», а говорилось о «связывании имён (name binding)», что было корректнее, но обескураживало новичков.
let x = foo();
Здесь происходит сопоставление с образцом, в результате которого значение выражения, которое вернул вызов foo(), сопоставляется с паттерном слева, состоящим только из одного нового имени x, в результате чего это имя связывается со всем значением.
let Point { x, y: b } = foo();
Здесь уже паттерн сложнее, новое имя x связывается со значением одноимённого поля экземпляра структуры Point, который возвращается вызовом foo(). А новое имя b связывается со значением поля y.
Так как это операция let и сопоставление полное, то введённые имена живут до конца текущего скоупа. Если нужно условное сопоставление, где новые имена будут жить только в новом скоупе (блоке), то можно использовать match или if let:
if let Some(val) = bar() {
println!("Можно использовать имя val = {val}");
}
...
match bar() {
Some(val) => println!("Можно использовать имя val = {val}"),
None => println!("Вызов вернул вариант None"),
}
Так что в Rust новые имена «переменных» могут вводиться только в составе образца в операциях: match, let, let ... else, if let, ... else if let, while let, for, в аргументах функций и замыканий. И больше - нигде. Для цикла for это приводит к довольно элегантным конструкциям:
for i in 0..5 {
println!("Iteration: {i}");
}
for (i, item) in [2, 5, 7].into_iter().enumerate() {
println!("Iteration: {i}, value: {item}");
}
Исходная версия freecoder, :
Вообще новые имена переменных в Rust вводятся только при сопоставлении и в составе образца! Это правило просто и универсально в рамках языка. В первой редакции Rust-book даже не было терминологии «ввести переменную», а говорилось о «связывании имён (name binding)», что было корректнее, но обескураживало новичков.
let x = foo();
Здесь происходит сопоставление с образцом, в результате которого значение выражения, которое вернул вызов foo(), сопоставляется с паттерном слева, состоящим только из одного нового имени x, в результате чего это имя связывается со всем значением.
let Point { x, y: b } = foo();
Здесь уже паттерн сложнее, новое имя x связывается со значением одноимённого поля экземпляра структуры Point, который возвращается вызовом foo(). А новое имя b связывается со значением поля y.
Так как это операция let и сопоставление полное, то введённые имена живут до конца текущего скоупа. Если нужно условное сопоставление, где новые имена будут жить только в новом скоупе (блоке), то можно использовать match или if let:
if let Some(val) = bar() {
println!("Можно использовать имя val = {val}");
}
...
match bar() {
Some(val) => println!("Можно использовать имя val = {val}"),
None => println!("Вызов вернул вариант None"),
}
Так что в Rust новые имена «переменных» могут вводиться только в составе образца в операциях: match, let, let ... else, if let, ... else if let, while let, for, в аргументах функций и замыканий. И больше - нигде. Для цикла for это приводит к довольно элегантным конструкциям:
for i in 0..5 {
println!("Iteration: {i}");
}
for (i, item) in [2, 5, 7].into_iter().enumerate() {
println!("Iteration: {i}, value: {item}");
}