мутабельные слайсы и borrow checker
От: sergii.p  
Дата: 15.02.23 10:12
Оценка:
споткнулся на такой забавный момент. Пока не понимаю причины
Такой код ругается на наличие изменяемой и неизменяемой ссылки одновременно
fn foo(nums: &mut[u32]) {
    todo!()
}

fn main() {
    let mut nums = [1, 2, 3, 4, 5, 6, 7];
    foo(&mut nums[0..nums.len() - 1]);
}


error[E0502]: cannot borrow `nums` as immutable because it is also borrowed as mutable
 --> src/main.rs:7:22
  |
7 |     foo(&mut nums[0..nums.len() - 1]);
  |              --------^^^^^^^^^^-----
  |              |       |
  |              |       immutable borrow occurs here
  |              mutable borrow occurs here
  |              mutable borrow later used here


а такой проходит нормально

fn main() {
    let mut nums = [1, 2, 3, 4, 5, 6, 7];
    let last = nums.len() - 1;
    foo(&mut nums[0..last]);
}


Мне казалось что первый код должен автоматом переходить во второй. Но получается диапазоны вносят какие-то модификации в этот алгоритм.
Re: мутабельные слайсы и borrow checker
От: T4r4sB Россия  
Дата: 15.02.23 13:12
Оценка: 4 (1)
Здравствуйте, sergii.p, Вы писали:

SP>Но получается диапазоны вносят какие-то модификации в этот алгоритм.


Дело не в диапазонах, а в том что несколько аргументов функции заимствуют массив. У тебЯ по сути код

Let arg1=&mut array;
Let arg2=array.somethimg;

Такой код запрещен
Сорян за форматирование пишу с телефона
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: мутабельные слайсы и borrow checker
От: johny5 Новая Зеландия
Дата: 15.02.23 20:26
Оценка: 6 (1)
Здравствуйте, sergii.p, Вы писали:

SP>
SP>fn main() {
SP>    let mut nums = [1, 2, 3, 4, 5, 6, 7];
SP>    foo(nums.split_last_mut().unwrap().1);
SP>}
SP>


Есть ещё такой вариант, не знаю правда можно ли его рекомендовать. Не блещет элегантностью и split делает чуть больше чем тебе нужно.
Зато unwrap() тут честен. Если массив пустой, видно что выстрелит явно. С range-ами тоже выстрелит но из кода это видно не так явно.
Re[2]: мутабельные слайсы и borrow checker
От: sergii.p  
Дата: 16.02.23 08:24
Оценка: -1 :)
Здравствуйте, johny5, Вы писали:

J>Есть ещё такой вариант, не знаю правда можно ли его рекомендовать. Не блещет элегантностью и split делает чуть больше чем тебе нужно.


интересный вариант. .1 только пугает. Не люблю такие конструкции. Это ж надо помнить, что там первый элемент, а что второй.
Да и вопрос был несколько в другом. Почему чекер здесь вообще ругается? Ответ вроде нашёл. Таки это "баг" компилятора, который ласково называют "ограничением". И учитывая, что живёт это давно, фиксить это никто не собирается.
Re[3]: мутабельные слайсы и borrow checker
От: T4r4sB Россия  
Дата: 16.02.23 08:31
Оценка:
Здравствуйте, sergii.p, Вы

> Почему чекер здесь вообще ругается? Ответ вроде нашёл. Таки это "баг" компилятора, который ласково называют "ограничением".


Странно я вроде дал тебе ответ что это не баг. Возражений не последовало. Но ты повторяешь свою претензию. Значит ты пришел поныть а не прлучить ответ. Держи минус
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: мутабельные слайсы и borrow checker
От: johny5 Новая Зеландия
Дата: 16.02.23 09:21
Оценка:
SP>интересный вариант. .1 только пугает. Не люблю такие конструкции. Это ж надо помнить, что там первый элемент, а что второй.
SP>Да и вопрос был несколько в другом. Почему чекер здесь вообще ругается? Ответ вроде нашёл. Таки это "баг" компилятора, который ласково называют "ограничением". И учитывая, что живёт это давно, фиксить это никто не собирается.

Ну да, это неприятный момент в компиляторе. Ну нужно просто привыкнуть.
Здесь это неудобно, зато это часть большой доказательной машины на уровне компилятора отсутствия data racing в коде.
Такие "баги" иногда фиксят, для каких то вот подобных примитивных случаев добавляют в язык какие то новые пункты в правило. В данном случае, просто поменяв порядок получения ссылки можно было бы избежать ошибки компилятора. Можно предложить им в форум но у ребят там тяжёлая работа — язык должен не терять лаконичности и сильно переусложняться правилами. Но я был бы рад если такое получилось бы добавить — в данном случае изменение не хитрое.
Re[4]: мутабельные слайсы и borrow checker
От: sergii.p  
Дата: 16.02.23 09:46
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Странно я вроде дал тебе ответ что это не баг. Возражений не последовало. Но ты повторяешь свою претензию. Значит ты пришел поныть а не прлучить ответ. Держи минус


так вы же ничего не ответили. Вопрос был почему 1-ый код не компилируется, 2-ой — нормально. Хотя они идентичны. Зачем надо подставлять костыли в виде let, чтобы заставить корректный код работать? Ответ "Такой код запрещен", извините, для десткого сада.
Правильный ответ лежит в плоскости non-lexical lifetimes
https://blog.rust-lang.org/2022/08/05/nll-by-default.html
То есть это реально ограничение borrow checker на данный момент.
Re: мутабельные слайсы и borrow checker
От: ArtDenis Россия  
Дата: 16.02.23 10:39
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>споткнулся на такой забавный момент. Пока не понимаю причины

SP>...
SP>Мне казалось что первый код должен автоматом переходить во второй. Но получается диапазоны вносят какие-то модификации в этот алгоритм.

Если в коде
fn main() {
    let mut nums = [1, 2, 3, 4, 5, 6, 7];
    let some_bad_ref = &mut nums[0..nums.len() - 1];
}


"рассахарить" последнюю строку, то получится

...
let some_bad_ref = std::ops::IndexMut::index_mut(&mut nums, 0..nums.len()-1);


Первый аргумент (&mut nums) функции IndexMut::index_mut уникально заимствует nums, поэтому во второй аргумент nums уже передать нельзя
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Отредактировано 16.02.2023 10:43 ArtDenis . Предыдущая версия . Еще …
Отредактировано 16.02.2023 10:41 ArtDenis . Предыдущая версия .
Re[5]: мутабельные слайсы и borrow checker
От: T4r4sB Россия  
Дата: 16.02.23 10:42
Оценка:
Здравствуйте, sergii.p,

SP>так вы же ничего не ответили.


Я написал, во что превращается вызов функции, когда аргументы — выражения которые надо вычислять.
Что непонятного?!

Напомню что параметры для вызова функции всегда считаются слева направо. Это важно.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Отредактировано 16.02.2023 10:53 T4r4sB . Предыдущая версия .
Re[2]: мутабельные слайсы и borrow checker
От: ArtDenis Россия  
Дата: 16.02.23 10:45
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Первый аргумент (&mut nums) функции IndexMut::index_mut уникально заимствует nums, поэтому во второй аргумент nums уже передать нельзя


Замечу ещё, что если бы self в расте передавался не первым аргументом функции, а последним, то код ТС компилировался без проблем
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[6]: мутабельные слайсы и borrow checker
От: sergii.p  
Дата: 16.02.23 11:51
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Напомню что параметры для вызова функции всегда считаются слева направо. Это важно.


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

let last = nums.len() - 1;
let slice = nums.index_mut(1..last);
foo(&mut slice);


и этот код вполне валиден. Короче, главный мой посыл: len вызывается до получения мутабельной ссылки, а не после. Нельзя получить slice без расчёта last.
Если бы было что-то вроде
foo(&mut nums, nums.len());

я бы даже согласился с такими доводами, хотя и то, не факт, что это мои проблемы разруливать здесь зависимости.
Re[7]: мутабельные слайсы и borrow checker
От: T4r4sB Россия  
Дата: 16.02.23 12:07
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>Здравствуйте, T4r4sB, Вы писали:


TB>>Напомню что параметры для вызова функции всегда считаются слева направо. Это важно.


SP>начал вас понимать, похоже. Только тут всё же немного не то. У нас один параметр в функции


Я не про функцию foo, а про функцию индексирования. У нее два параметра; ссылка на масств и число.
Как тут написалы выше, оператор [] это сахарок а на деле это вызов функции с двумя параметрами
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: мутабельные слайсы и borrow checker
От: T4r4sB Россия  
Дата: 16.02.23 12:10
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Здравствуйте, ArtDenis, Вы писали:


AD>>Первый аргумент (&mut nums) функции IndexMut::index_mut уникально заимствует nums, поэтому во второй аргумент nums уже передать нельзя


AD>Замечу ещё, что если бы self в расте передавался не первым аргументом функции, а последним, то код ТС компилировался без проблем


Вообще это жирный фейл, ведь паттерн

selm.mutable_method(self.smth)

довольно распространен.
Для него моглы бы и подправить борзочекер
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[4]: мутабельные слайсы и borrow checker
От: ArtDenis Россия  
Дата: 16.02.23 12:18
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Вообще это жирный фейл


В расте ещё немало вещей, которые ставят в тупик, если не понимаешь каких-то основ. Но слава богу их меньше чем в тех же плюсах )
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[8]: мутабельные слайсы и borrow checker
От: sergii.p  
Дата: 16.02.23 18:09
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Я не про функцию foo, а про функцию индексирования. У нее два параметра; ссылка на масств и число.

TB>Как тут написалы выше, оператор [] это сахарок а на деле это вызов функции с двумя параметрами

да, ок, упустил из виду. Хотя из первого сообщения, согласитесь, это было не понять.
Re[5]: мутабельные слайсы и borrow checker
От: T4r4sB Россия  
Дата: 16.02.23 18:11
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>В расте ещё немало вещей, которые ставят в тупик, если не понимаешь каких-то основ.)


Или просто багов.

https://users.rust-lang.org/t/strange-borrow-checker-behavior-when-returning-content-of-option/88982
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.