CodeBlanks Logo Icon CodeBlanks

Pin

Pin<T> ve self-referanslı verilerin önemini öğrenirsin.

Pin

Async fonksiyonların durum makineleri kendi içlerine referans tutabilir (örneğin .await öncesi alınan bir referans). Böyle bir değer bellekte taşınırsa içteki referans eski adresi gösterir. Pin<P>, gösterdiği değerin artık taşınmayacağını garanti eder; bu yüzden poll self: Pin<&mut Self> alır.

let f = async { 42 };
let mut kutulu = Box::pin(f);           // heap'te sabitlendi
let mut yerel = std::pin::pin!(async { 1 });   // stack'te sabitlendi

Çoğu tür (i32, String, Vec) Unpin'dir: taşınmaları güvenlidir ve Pin onlar için bir kısıt getirmez.

Kutulu Future'lar

Pin<Box<dyn Future>> kendisi Unpin'dir ve Future uygular; bu yüzden doğrudan block_on'a verilebilir. Özyinelemeli async fonksiyonlar ve trait'lerden Future döndürmek de bu türle yapılır:

type KutuluFuture = Pin<Box<dyn Future<Output = i32>>>;

let isler: Vec<KutuluFuture> = vec![
    Box::pin(async { 1 }),
    Box::pin(async { 2 }),
];
let toplam: i32 = isler.into_iter().map(block_on).sum();

Uygulama Kutulu iş listesi

type KutuluFuture = Pin<Box<dyn Future<Output = i32>>>; tanımla. async { 1 } ve async { 2 } bloklarını Box::pin ile bir Vec<KutuluFuture>'e koy, her birini block_on ile çalıştırıp topla ve yazdır.

Başlangıç kodu

main.rs
use std::future::Future;
use std::pin::{pin, Pin};
use std::task::{Context, Poll, Waker};

fn block_on<F: Future>(f: F) -> F::Output {
    let mut f = pin!(f);
    let mut cx = Context::from_waker(Waker::noop());
    loop {
        if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
            return v;
        }
    }
}

fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
use std::future::Future;
use std::pin::{pin, Pin};
use std::task::{Context, Poll, Waker};

fn block_on<F: Future>(f: F) -> F::Output {
    let mut f = pin!(f);
    let mut cx = Context::from_waker(Waker::noop());
    loop {
        if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
            return v;
        }
    }
}

type KutuluFuture = Pin<Box<dyn Future<Output = i32>>>;

fn main() {
    let isler: Vec<KutuluFuture> = vec![Box::pin(async { 1 }), Box::pin(async { 2 })];
    let toplam: i32 = isler.into_iter().map(block_on).sum();
    println!("{}", toplam);
}

Beklenen çıktı

3

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Farklı async bloklardan oluşan bir listeyi tek bir <code>Vec</code>'te tutmak için hangi tür kullanılır?

  • &dyn Future
  • Pin<Box<dyn Future<Output = T>>> Doğru cevap
  • Vec<impl Future>
  • Box<Future>

Açıklama: Her async blok ayrı bir türdür; trait nesnesi ile ortak türe getirilir, Box::pin ile sabitlenir.

2 Heap'te sabitle

Soru
let mut kutulu = Box::____(async { 42 });
Cevap
let mut kutulu = Box::pin(async { 42 });

Açıklama: Box::pin değeri heap'e koyar ve sabitler.

3 Kavram ve anlamı

Kavram Anlamı
Pin<P> Taşınmama garantisi
Unpin Taşınması güvenli
Box::pin Heap'te sabitler
pin! Stack'te sabitler

İleri seviye bölümündeki tüm dersler