Каковы варианты использования нового типа Pin?

В нестабильном Rust есть новый тип Pin и RFC уже слит. Говорят, что это своего рода игровой чейнджер, когда речь заходит о передаче ссылок, но я не уверен, как и когда его следует использовать.

Может ли кто-нибудь объяснить это в непрофессиональных условиях?

Ответы

Ответ 1

Что пиннинг?

При программировании закрепление X означает указание X не двигаться.

Например:

  • Привязка потока к ядру процессора, чтобы он всегда выполнялся на одном CPU,
  • Закрепление объекта в памяти, чтобы предотвратить сборщик мусора для его перемещения (например, в С#).

Что такое тип Pin?

Назначение типа Pin заключается в том, чтобы связать объект с памятью.

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

Что это за дела?

Основная утилита, для которой она была разработана, поддерживает генераторы.

Идея генераторов состоит в том, чтобы написать простую функцию с yield, а компилятор автоматически перевести эту функцию в конечный автомат. Состояние, которое несет генератор, представляет собой "стек" переменных, которые необходимо сохранить от одного вызова к другому.

Основная сложность генераторов, для которых Pin предназначена для исправления, заключается в том, что генераторы могут в конечном итоге хранить ссылку на один из своих собственных членов данных (в конце концов, вы можете создавать ссылки на значения стека) или ссылку на объект, в конечном счете принадлежащий их собственным данных (например, a &T полученных из Box<T>).

Это подканал самореферентных структур, которые до сих пор требовали настраиваемые библиотеки (и много unsafe). Проблема самореферентных структур заключается в том, что если перемещение структуры, содержащаяся ссылка все еще указывает на старую память.

Pin видимому, Pin решает этот многолетний вопрос о ржавчине. Как тип библиотеки. Это создает дополнительную гарантию того, что до тех пор, пока Pin существует, закрепленное значение не может быть перемещено.

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

Ответ 2

Одним из возможных видов использования типа Pin является объект саморегуляции; статья ralfj представляет собой пример структуры SelfReferential которая была бы очень сложной без него:

#![feature(pin, arbitrary_self_types, optin_builtin_traits)]

use std::ptr;
use std::mem::Pin;
use std::boxed::PinBox;
use std::marker::Unpin;

struct SelfReferential {
    data: i32,
    self_ref: *const i32,
}

impl !Unpin for SelfReferential {}

impl SelfReferential {
    fn new() -> SelfReferential {
        SelfReferential { data: 42, self_ref: ptr::null()  }
    }

    fn init(mut self: Pin<SelfReferential>) {
        let this : &mut SelfReferential = unsafe { Pin::get_mut(&mut self) };
        // Set up self_ref to point to this.data.
        this.self_ref = &mut this.data as *const i32;
    }

    fn read_ref(mut self: Pin<SelfReferential>) -> Option<i32> {
        let this : &mut SelfReferential = unsafe { Pin::get_mut(&mut self) };
        // Dereference self_ref if it is non-NULL.
        if this.self_ref == ptr::null() {
            None
        } else {
            Some(unsafe { *this.self_ref })
        }
    }
}

fn main() {
    let mut s = PinBox::new(SelfReferential::new());
    s.as_pin().init();
    println!("{:?}", s.as_pin().read_ref()); // prints Some(42)
}