Как изменить значение Arc<u64> в структуре?

Я не могу увеличить значение внутри структуры. Я получаю много разных ошибок компиляции. У меня есть неизменяемая ссылка на 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

По-видимому, примеры в документации будут работать только для переменных, но не для структур, так как же это сделать со структурами?

Немного сложно ответить на ваш вопрос, потому что он не включает минимальный воспроизводимый пример. Мы не можем сказать, какие крейты (и их версии), типы, трейты, поля и т. д. присутствуют в коде. Нам будет намного легче помочь, если вы попытаетесь воспроизвести свою ошибку на Детская площадка ржавчины, если это возможно, в противном случае в совершенно новом проекте Cargo, тогда редактировать ваш вопрос, чтобы включить дополнительную информацию. Есть Советы по MCVE для Rust, которые вы можете использовать, чтобы уменьшить исходный код для публикации здесь. Спасибо!

Shepmaster 21.05.2019 02:31
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
2
1
2 754
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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);
}

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

Похожие вопросы

Почему библиотека WASM в Rust должна устанавливать тип контейнера как cdylib?
Могу ли я десериализовать векторы с префиксом переменной длины с помощью Bincode?
Возврат замыкания из замыкания в качестве возвращаемого значения для функции
Сообщает ли компилятору, возвращающему тип со значением 'static, что это значение не имеет связанного времени жизни, или оно делает это значение статическим?
Как я могу реализовать сложные макросы, такие как `format_args!`, в пользовательском пространстве?
Простая реализация для получения итератора первого слова каждой строки ввода
Как кросс-компилировать код Rust для Raspberry Pi Zero W
Передача String::as_str в Option<String>::map() не компилируется с ошибкой несоответствия типов
Можно ли выполнить деструктурирование присваивания с аннотациями типов?
Как сделать, чтобы мой пользовательский производный макрос принимал общие параметры трейта?