Pin
- Rust kursu
- İleri seviye
- Ders 5/81
- 4 dk
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
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
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
let mut kutulu = Box::____(async { 42 });
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 |