Страницы

Поиск по вопросам

воскресенье, 8 марта 2020 г.

Rust. Вызов метода у Arc<T>

#rust #mutex


Читаю Rustbook и не понимаю некоторые вещи.     

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
    for i in 0..3 {
        let data = data.clone(); //(1)
        thread::spawn(move || {
            let mut data = data.lock().unwrap(); //(2)
            data[i] += 1;
        });
    }
    thread::sleep_ms(50);
}


(1). Метод clone() возвращает тип self, т.е. Arc<_>. В этом можно убедиться, если
явно написать тип:

let data: Arc>> = data.clone();


В связи с этим возникает вопрос: почему в (2) мы вызываем метод lock() так, если
бы мы работали напрямую с Mutex? Все как в C++, но там у shared_ptr оператор -> перегружен
за нас, а покопавшись в исходниках arc.rs я не увидел подобного или пропустил.

UPD

Спасибо Кнопкатык за наводку на Deref coercions. Для закрепления написал такой искусственный
пример:

use std::ops::Deref;

#[derive(Debug)]
struct Field {
    x: i32,
}

impl Field{
    fn print(&self){
        println!("x = {}", self.x);
    }
}

#[derive(Debug)]
struct Example {
    x: Field,
}

impl Deref for Example{
    type Target = Field;

    fn deref(&self) -> &Field{
        &self.x
    }
}

fn main() {
    let s = Example { x: Field { x: 5} };
    s.print();
}


Структура Example не имеет имплементации метода print.
Но если вспомнить универсальный синтаксис вызова функций, то 

s.print();


можно заменить на:

Field::print(&s);


Следовательно, так как у нас есть реализация типажа Deref для Example, возвращающая
&Field, то значения Example, если нужно, будут автоматически преобразовываться в &Field
при разыменовании:

Field::print(&Example) -> dereference -> Field::print(&Field);


Код, как и предполагается, выведет:

x = 5

    


Ответы

Ответ 1



Дело в механизме Deref coercions или "Преобразования при разыменовании". Arc реализует типаж Deref, значения &Arc будут автоматически преобразованы в &T, когда это необходимо. Метод lock(&self) Мютекса принимает &self, и когда мы пытаемся вызвать его с Arc: lock(&Arc) срабатывает механизм Deref coercions lock(&Mutex) а &Mutex это и есть &self для метода lock.

Комментариев нет:

Отправить комментарий