LINUX.ORG.RU

Shadowing Rust

 ,


0

5

Всем привет. Разбираюсь с Rust. Наткнулся на shadowing. Вот пример:

    let x = 15;
    println!("x is {}", x);
    let x = 42;
    println!("x is {}", x);
    let x = "A String";
    println!("x is {}", x);
    let x = true;
    println!("x is {}", x);
Я понимаю в сях, питоне или еще где, затенение в отдельных блоках, в ржавчине это тоже есть, но затенение в еще и этом виде, мне кажется может вызвать ошибки в коде. Кроме того, мне сложно представить как это использовать в реальном коде, кроме как let x = x + 1 в каких-нибудь циклах, но в расте из функциональщины достаточно отличных функций, потому вообще не могу представить чтобы в циклах надо было инкрементить переменные. В общем, есть ли реальные причины такого затенения в раст? Или это наследование из ML?

Еще, например, в этом коде:

let mut guess = String::new();
let mut guess = String::new();

Освобождение памяти для переменной из верхней строки будет когда дело дойдет до второй или я не прав? Не потечет ли память, если она не освобождается на второй строке? А если там не string, а моя структура со своей реализацией drop, где я не освобождаю память явно, ржавчина достаточно умен чтобы удалить все за меня?



Последнее исправление: Gro (всего исправлений: 2)

Синтаксис let — это привязка (binding) к объекту на стеке. Время жизни объекта, определяется областью видимости.

{ // lifetime
    let x = 0;
    let y = &x; // reference to x = 0
    let x = 1;
    let z = &x; // reference to x = 1

    assert_eq!(*y, 0);
    assert_eq!(*z, 1);
    // destroy z, x = 1, y, x = 0
}

Типичный пример, где это может пригодиться.

let mut age = String::new();
io::stdin().read_line()?;
let age: Option<u32> = age.trim().parse().ok();
anonymous
()
Ответ на: комментарий от anonymous

В — внимательность. Поправил пример.

let mut age = String::new();
io::stdin().read_line(&mut age)?;
let age: Option<u32> = age.trim().parse().ok();
anonymous
()

Освобождение памяти для переменной из верхней строки будет когда дело дойдет до второй или я не прав?

Почему бы самому не проверить?

struct A(u32);

impl Drop for A {
    fn drop(&mut self) {
        println!("A({}) уничтожена", self.0);
    }
}

fn main() {
    let a = A(0);
    println!("A(0) создана");
    let a = A(1);
    println!("A(1) создана");
}

Результат

A(0) создана
A(1) создана
A(1) уничтожена
A(0) уничтожена

Переменные уничтожаются в конце блока в порядке обратном объявлению.

red75prim ★★★
()
Последнее исправление: red75prim (всего исправлений: 1)

Кроме того, мне сложно представить как это использовать в реальном коде

Ну, например, let foo = tranform_foo(foo, ...). Так не требуется плодить имена для различных форм одного и того же.

кроме как let x = x + 1 в каких-нибудь циклах

Вот так как раз не получится делать. `let x` не меняет `x`.

quantum-troll ★★★★★
()

Реальный пример, это когда ты читаешь от куда либо данные (например, из json по сети), а потом их преобразовываешь (например, строка в число). Это позволяет не создавать стопитьсоц переменных (например, 1 для json, 1 для строки, 1 для числа) ради данных которые логически едины, а просто затеняешь предыдущее состояние.

AntonyRF ★★★★
()
Ответ на: комментарий от AntonyRF

Реальный пример, это когда ты читаешь от куда либо данные (например, из json по сети), а потом их преобразовываешь (например, строка в число). Это позволяет не создавать стопитьсоц переменных (например, 1 для json, 1 для строки, 1 для числа) ради данных которые логически едины, а просто затеняешь предыдущее состояние

А можно просто написать композицию трёх функций, и ничего затенять не придётся

Crocodoom ★★★★★
()

Кроме того, мне сложно представить как это использовать в реальном коде, кроме как let x = x + 1 в каких-нибудь циклах, но в расте из функциональщины достаточно отличных функций, потому вообще не могу представить чтобы в циклах надо было инкрементить переменные.

Ты в курсе про мутабельные переменные?

let mut x = 1;
x = x + 1;

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

А можно просто написать композицию трёх функций, и ничего затенять не придётся

Бывает, что промежуточное значение тоже нужно для чего-нибудь, но только в этом месте, например, записать его размер в байтах для лога или статистики какой.

anonymous
()
Ответ на: комментарий от Crocodoom

А можно просто написать композицию трёх функций

А можно не писать. Большое количество однострочных функций, которые используются ровно один раз, не способствуют читабельности кода.

Deleted
()
Ответ на: комментарий от Deleted

Если они правда однострочные, то и незачем их отдельно куда-то выносить (и как-то специально называть) - всё делается на месте, при помощи функциональщины.

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

А можно просто написать композицию трёх функций, и ничего затенять не придётся

Можно, но не нужно. В общем случае, композиция выглядет хорошо только в конкатенативных языках.

quantum-troll ★★★★★
()
Ответ на: комментарий от Crocodoom

Три скрывающих присваивания могут выглядеть гораздо более читаемо, нежели inline композиция из трёх функций.

Dark_SavanT ★★★★★
()
Ответ на: комментарий от Crocodoom

всё делается на месте, при помощи функциональщины

А можно конкретный пример где это делает код проще и понятней? Только не на чисто функциональных ЯП, в которых писание императивного кода по определению причиняет боль.

Deleted
()
Ответ на: комментарий от Deleted

А можно конкретный пример где это делает код проще и понятней? Только не на чисто функциональных ЯП

Если про Rust, то цепочки итераторов + лямбды. Пример кода здесь.
Даже завезли в язык специальный for_each ради единства стиля.
Попробуй переписать код, используя «затенение переменной», если хочешь.

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Это всё отлично, но какое имеет отношение к

Реальный пример, это когда ты читаешь от куда либо данные (например, из json по сети), а потом их преобразовываешь (например, строка в число). Это позволяет не создавать стопитьсоц переменных (например, 1 для json, 1 для строки, 1 для числа) ради данных которые логически едины, а просто затеняешь предыдущее состояние

?

Deleted
()
Ответ на: комментарий от Deleted

Это пример, когда многократное затенение преобразованного состояния заменяется многократной композицией функций. Ровно об этом мы и говорили. Если тебе нужно что-то другое, то уточняй.

Crocodoom ★★★★★
()

1. Утечки тут нет.

2. Удобно. Я очень часто использую.

RazrFalcon ★★★★★
()
Ответ на: комментарий от Crocodoom

А можно просто написать композицию трёх функций, и ничего затенять не придётся

Ну уж нет, библиотеки Rust позволяют не писать много кода и не плодить миллион функций, чему я очень рад.

AntonyRF ★★★★
()
Ответ на: комментарий от Crocodoom

Мы тут говорим про простые случаи вида

let x = 123;
let x: ДругойТип = сделать_что_то(x);
let x: ЕщёТип = сделать_что_то_ещё(x);
x

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

Мы тут говорим про простые случаи вида

let x = 123;
let x: ДругойТип = сделать_что_то(x);
let x: ЕщёТип = сделать_что_то_ещё(x);
x

Ок. Чем это лучше сделать_что_то_ещё(сделать_что_то(123))?

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Гарантией влезания в экран и лучшей читабельностью для тех, кто читает слева направо и сверху вниз.

Deleted
()
Ответ на: комментарий от Crocodoom

Проблема в лайфтамах. Может ругаться на то, что временный объект живёт слишком мало.

Ну и в diff'ах будет красивее.

RazrFalcon ★★★★★
()
Ответ на: комментарий от Crocodoom

1. Прямой порядок выполнения
2. Функция может возвращать или принимать несколько значений
3. Первоначально, x может быть результатом сопоставления с образцом.

quantum-troll ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.