Я пытаюсь реализовать сито эратосфенов, оно находит все пирмы ниже 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, в то время как он все еще заимствован внешним циклом. Поэтому мне нужно каким-то образом передать право собственности на заимствование внутреннему циклу, чтобы он мог отмечать кратные значения. Как мне это сделать?
Вместо того, чтобы перебирать значения в is_prime во внешнем цикле, вы можете просто перебирать индексы (for index in (3..marking_lim).step_by(2)) и заимствовать is_prime только при необходимости, извлекая val через индекс (is_prime[index]). Тогда вы сможете свободно заимствовать is_prime во внутреннем цикле.
@AspectOfTheNoob, потому что я изменяю значения. смотри строчку *val_2 = false
@ Pioneer_11 Но вы не изменяете val из внешнего цикла.
@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) } <- компилируется
Я не понимаю, как это связано. Почему нельзя использовать iter() для внешнего цикла?
@ChayimFriedman, потому что тогда он был бы неизменно заимствован во внешнем цикле, тогда как внутренний цикл не может заимствовать те же данные без изменений. В данный момент это не работает, но, как я уже сказал в вопросе, я ищу способ передать право собственности на внешнее заимствование внутреннему заимствованию, что мне кажется единственным решением. Если это может быть выполнено, то внутреннему циклу потребуется изменяемая ссылка, поэтому, если я передаю право собственности на ссылку во внешнем цикле, тогда эта ссылка должна быть изменяемой.
Невозможно сделать именно то, что вы просите. Самое простое решение — избегать заимствования 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);
}
}
}
Спасибо, я предполагаю, что ячейка - это какой-то контейнер с подсчетом ссылок?
Зачем нужен изменяемый итератор?