Передать право собственности во вложенном цикле

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

Мой код для шага маркировки:

for (index, val) in is_prime[3..marking_lim].iter_mut().step_by(2).enumerate() {     // borrow of is_prime
    if *val == true {
       primes_found.push(index as i32);           // add the prime to the list
       n_found += 1;                               // counter for primes found, cannot be exceeded in this step
       for val_2 in is_prime[index..(up_to_nth as usize)].iter_mut().step_by(index) {   // second borrow of is_prime
            *val_2 = false;
        }
    }
}

Однако это не работает, так как внутренний цикл принимает изменяемое заимствование is_prime, в то время как он все еще заимствован внешним циклом. Поэтому мне нужно каким-то образом передать право собственности на заимствование внутреннему циклу, чтобы он мог отмечать кратные значения. Как мне это сделать?

Зачем нужен изменяемый итератор?

AspectOfTheNoob 11.01.2023 00:57

Вместо того, чтобы перебирать значения в is_prime во внешнем цикле, вы можете просто перебирать индексы (for index in (3..marking_lim).step_by(2)) и заимствовать is_prime только при необходимости, извлекая val через индекс (is_prime[index]). Тогда вы сможете свободно заимствовать is_prime во внутреннем цикле.

EvilTak 11.01.2023 01:05

@AspectOfTheNoob, потому что я изменяю значения. смотри строчку *val_2 = false

Pioneer_11 11.01.2023 01:08

@ Pioneer_11 Но вы не изменяете val из внешнего цикла.

Chayim Friedman 11.01.2023 03:33

@ChayimFriedman да. Однако из-за системы заимствования Rust «много неизменяемых или один изменяемый» невозможно превратить неизменяемую ссылку в изменяемую ссылку. Однако можно передать право собственности на изменяемую ссылку от одной переменной к другой fn main() { let mut test_arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let a = &test_arr; let b = &mut a; } <-- недопустимо, не компилируется fn main() { let mut test_arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let a = &mut test_arr; let b = a; b[2] += 10; println!("{:?}", b) } <- компилируется

Pioneer_11 11.01.2023 07:08

Я не понимаю, как это связано. Почему нельзя использовать iter() для внешнего цикла?

Chayim Friedman 11.01.2023 07:12

@ChayimFriedman, потому что тогда он был бы неизменно заимствован во внешнем цикле, тогда как внутренний цикл не может заимствовать те же данные без изменений. В данный момент это не работает, но, как я уже сказал в вопросе, я ищу способ передать право собственности на внешнее заимствование внутреннему заимствованию, что мне кажется единственным решением. Если это может быть выполнено, то внутреннему циклу потребуется изменяемая ссылка, поэтому, если я передаю право собственности на ссылку во внешнем цикле, тогда эта ссылка должна быть изменяемой.

Pioneer_11 12.01.2023 06:31
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Невозможно сделать именно то, что вы просите. Самое простое решение — избегать заимствования is_prime во внешнем цикле:

for (index, index_2) in (3..marking_lim).step_by(2).enumerate() {
    if is_prime[index_2] {
        // ...

Более причудливое решение — использовать std::cell::Cell, что позволяет изменять элементы массива с помощью ссылки, отличной от mut:

use std::cell::Cell;

let is_prime = Cell::from_mut(&mut is_prime[..]).as_slice_of_cells();

for (index, val) in is_prime[3..marking_lim].iter().step_by(2).enumerate() {
    if val.get() {
        primes_found.push(index as i32);
        n_found += 1;
        for val_2 in is_prime[index..(up_to_nth as usize)].iter().step_by(index) {
            val_2.set(false);
        }
    }
}

Спасибо, я предполагаю, что ячейка - это какой-то контейнер с подсчетом ссылок?

Pioneer_11 13.01.2023 12:49

Это не подсчитывается ссылка; это обертка с нулевой стоимостью. Компромиссы: 1. Это не потокобезопасно. 2. Общая ячейка не позволяет получить прямую ссылку на ее содержимое (учитывая &Cell<T>, вы не можете получить &T или &mut T). Вот почему я должен использовать в коде методы ячейки get() и set(), при этом get() копирует значение из ячейки вместо возврата ссылки.

Brian Bowman 13.01.2023 19:26

Другие вопросы по теме