Я не могу увеличить значение внутри структуры. Я получаю много разных ошибок компиляции. У меня есть неизменяемая ссылка на self
, и я не могу сделать ее изменяемой.
Вот моя структура:
/// Proposer factory.
pub struct ProposerFactory<C, A>
where
A: txpool::ChainApi,
{
/// The client instance.
pub client: Arc<C>,
/// The transaction pool.
pub transaction_pool: Arc<TransactionPool<A>>,
/// The inherents pool
pub inherents_pool: Arc<InherentsPool<<A::Block as BlockT>::Extrinsic>>,
/// Current queue number
cur_queue_no_ptr: Arc<u64>,
}
Я хочу увеличить cur_queue_no_ptr
на +1
Я пробовал этот код:
let old_value_ref = Arc::get_mut(&mut self.cur_queue_no_ptr).unwrap();
let old_value = *old_value_ref;
let new_value = old_value + 1;
но получил эту ошибку:
152 | let old_value_ref=Arc::get_mut(&mut self.cur_queue_no_ptr).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
Я пробовал этот код:
let copied_arc = Arc::clone(&self.cur_queue_no_ptr);
let old_value = *Arc::make_mut(&mut copied_arc);
let new_value = old_value + 1;
И еще ошибка:
150 | let old_value = *Arc::make_mut(&mut copied_arc);
| ^^^^^^^^^^^^^^^ cannot borrow as mutable
Я также пытался с RefCell
, но я получаю эту ошибку:
^^^^^ `std::cell::RefCell<u64>` cannot be shared between threads safely
По-видимому, примеры в документации будут работать только для переменных, но не для структур, так как же это сделать со структурами?
Arc
позволяет вам получить изменяемую ссылку на содержимое только в том случае, если у вас есть изменяемая ссылка на сам объект Arc
, а Arc
— это Только, который указывает на его содержимое (все остальные уже удалены).
Здесь вам нужен один из эквивалентов RefCell
для потокобезопасного кодирования, а именно Mutex
или RwLock
. Они заблокируют доступ к содержимому, пока вы его берете, чтобы вы могли безопасно получать к нему доступ из нескольких потоков одновременно:
use std::sync::{Arc, Mutex};
fn example() {
// defining the counter variable
let counter = Arc::new(Mutex::new(0));
// lock the mutex to borrow
// it is automatically released when the borrow ends
let mut counter_lock = counter.lock().unwrap();
*counter_lock = *counter_lock + 1;
}
Mutex
позволяет вам заимствовать только изменчиво, что делает его проще, но иногда этого недостаточно. RwLock
позволяет вам также неизменно заимствовать, так что вы можете иметь либо одно изменяемое заимствование, либо несколько неизменяемых заимствований.
В качестве альтернативы для числовых типов может быть предпочтительнее использовать атомарные типы. Они специально созданы для целых чисел и работают быстрее, чем Mutex
или RwLock
(поскольку им не нужно ничего блокировать, изменения происходят атомарно). Для счетчика, как указано выше, соответствующий пример будет выглядеть примерно так:
use std::sync::{
atomic::{AtomicU32, Ordering},
Arc,
};
fn example() {
// define the counter variable
let counter = Arc::new(AtomicU32::new(0));
// increment the counter
// no lock or mutable borrow is necessary
counter.fetch_add(1, Ordering::SeqCst);
}
Немного сложно ответить на ваш вопрос, потому что он не включает минимальный воспроизводимый пример. Мы не можем сказать, какие крейты (и их версии), типы, трейты, поля и т. д. присутствуют в коде. Нам будет намного легче помочь, если вы попытаетесь воспроизвести свою ошибку на Детская площадка ржавчины, если это возможно, в противном случае в совершенно новом проекте Cargo, тогда редактировать ваш вопрос, чтобы включить дополнительную информацию. Есть Советы по MCVE для Rust, которые вы можете использовать, чтобы уменьшить исходный код для публикации здесь. Спасибо!