LINUX.ORG.RU

История изменений

Исправление 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}");
}

Запустить: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f3f1da4e52def36e39f33103e15e9fa8

Исправление 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}");
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=f3f1da4e52def36e39f33103e15e9fa8

Исходная версия 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}");
}