Rust: [Stabilisasi] Pin API

Dibuat pada 7 Nov 2018  ·  213Komentar  ·  Sumber: rust-lang/rust

@rachmandfc_gabung
Nama fitur: pin
Target stabilisasi: 1.32.0
Masalah pelacakan: # 49150
RFC terkait: rust-lang / rfcs # 2349

Ini adalah proposal untuk menstabilkan fitur perpustakaan pin , membuat "penyematan"
API untuk memanipulasi memori tersemat yang dapat digunakan di stable.

(Saya telah mencoba menulis proposal ini sebagai "laporan stabilisasi" yang komprehensif.)

Fitur atau API yang distabilkan

[std|core]::pin::Pin

Ini menstabilkan tipe Pin di submodul pin dari std / core . Pin adalah
dasar, pembungkus transparan di sekitar tipe generik P , yang dimaksudkan
menjadi tipe penunjuk (misalnya, Pin<&mut T> dan Pin<Box<T>> keduanya
valid, konstruksi yang dimaksudkan). Pin wrapper mengubah pointer menjadi "pin"
memori yang dirujuk pada tempatnya, mencegah pengguna memindahkan objek keluar
dari memori itu.

Cara biasa untuk menggunakan tipe Pin adalah dengan membuat varian tersemat dari beberapa
jenis memiliki pointer ( Box , Rc , dll). Perpustakaan std memiliki semua petunjuk
menyediakan konstruktor pinned yang mengembalikan ini. Kemudian, untuk memanipulasi file
nilai di dalamnya, semua petunjuk ini memberikan cara untuk menurunkan ke arah Pin<&T>
dan Pin<&mut T> . Pointer yang dipasangi pin dapat dilakukan, memberi Anda &T , tetapi tidak bisa
aman saling deref: ini hanya mungkin menggunakan tidak aman get_mut
fungsi.

Akibatnya, siapa pun yang memutasikan data melalui pin akan diwajibkan untuk menjunjung
berbeda bahwa mereka tidak pernah keluar dari data itu. Ini memungkinkan kode lain untuk
dengan aman berasumsi bahwa data tidak pernah dipindahkan, memungkinkannya berisi (untuk
contoh) referensi diri.

Jenis Pin akan memiliki API yang distabilkan ini:

impl<P> Pin<P> where P: Deref, P::Target: Unpin

  • fn new(pointer: P) -> Pin<P>

impl<P> Pin<P> where P: Deref

  • unsafe fn new_unchecked(pointer: P) -> Pin<P>
  • fn as_ref(&self) -> Pin<&P::Target>

impl<P> Pin<P> where P: DerefMut

  • fn as_mut(&mut self) -> Pin<&mut P::Target>
  • fn set(&mut self, P::Target);

impl<'a, T: ?Sized> Pin<&'a T>

  • unsafe fn map_unchecked<U, F: FnOnce(&T) -> &U>(self, f: F) -> Pin<&'a U>
  • fn get_ref(self) -> &'a T

impl<'a, T: ?Sized> Pin<&'a mut T>

  • fn into_ref(self) -> Pin<&'a T>
  • unsafe fn get_unchecked_mut(self) -> &'a mut T
  • unsafe fn map_unchecked_mut<U, F: FnOnce(&mut T) -> &mut U>(self, f: F) -> Pin<&'a mut U>

impl<'a, T: ?Sized> Pin<&'a mut T> where T: Unpin

  • fn get_mut(self) -> &'a mut T

Trait impls

Sebagian besar ciri yang tersirat pada Pin cukup hafal, keduanya penting untuk
operasinya:

  • impl<P: Deref> Deref for Pin<P> { type Target = P::Target }
  • impl<P: DerefMut> DerefMut for Pin<P> where P::Target: Unpin { }

std::marker::Unpin

Lepas pin adalah sifat otomatis aman yang menyisih dari jaminan penyematan. Jika
target dari penunjuk yang disematkan mengimplementasikan Unpin , itu aman untuk berubah-ubah
dereferensi untuk itu. Unpin tipe tidak memiliki jaminan bahwa mereka tidak akan memilikinya
dipindahkan dari Pin .

Hal ini menjadikannya sebagai ergonomis untuk menangani referensi yang disematkan ke sesuatu itu
tidak berisi referensi mandiri karena akan menangani non-pin
referensi. Jaminan Pin hanya berlaku untuk jenis kasus khusus seperti
struktur referensi sendiri: tipe tersebut tidak mengimplementasikan Unpin , jadi mereka memilikinya
pembatasan tipe Pin .

Implementasi penting dari Unpin di std:

  • impl<'a, T: ?Sized> Unpin for &'a T
  • impl<'a, T: ?Sized> Unpin for &'a mut T
  • impl<T: ?Sized> Unpin for Box<T>
  • impl<T: ?Sized> Unpin for Rc<T>
  • impl<T: ?Sized> Unpin for Arc<T>

Ini mengkodifikasi gagasan bahwa penyematan tidak transitif lintas pointer. Bahwa
adalah, Pin<&T> hanya menyematkan blok memori aktual yang diwakili oleh T dalam file
tempat. Pengguna terkadang bingung dengan ini dan mengharapkan sebuah tipe
seperti Pin<&mut Box<T>> menyematkan data T pada tempatnya, tetapi hanya menyematkan
memori referensi yang disematkan sebenarnya merujuk ke: dalam hal ini, Box
representasi, yang merupakan penunjuk ke heap.

std::marker::Pinned

Tipe Pinned adalah ZST yang tidak mengimplementasikan Unpin ; itu memungkinkan Anda untuk
tekan implementasi otomatis Unpin pada stabil, di mana !Unpin impls
belum stabil.

Konstruktor penunjuk cerdas

Konstruktor ditambahkan ke std smart pointer untuk membuat referensi yang disematkan:

  • Box::pinned(data: T) -> Pin<Box<T>>
  • Rc::pinned(data: T) -> Pin<Rc<T>>
  • Arc::pinned(data: T) -> Pin<Arc<T>>

Catatan tentang penyematan & keamanan

Selama 9 bulan terakhir, API penyematan telah melalui beberapa iterasi sebagai
kami telah menyelidiki kekuatan ekspresif mereka dan juga kesehatan mereka
jaminan. Sekarang saya akan mengatakan dengan yakin bahwa API penyematan stabil di sini
sehat dan cukup dekat dengan maksimal lokal dalam ergonomi dan
ekspresi; yaitu, siap untuk stabilisasi.

Salah satu masalah tersulit dari pemasangan pin adalah menentukan kapan aman untuk dilakukan
proyeksi pin : yaitu, beralih dari Pin<P<Target = Foo>> ke a
Pin<P<Target = Bar>> , di mana Bar adalah bidang Foo . Untungnya, kami punya
mampu mengkodifikasi seperangkat aturan yang dapat membantu pengguna menentukan apakah seperti itu
proyeksi aman:

  1. Aman untuk menyematkan proyek jika (Foo: Unpin) implies (Bar: Unpin) : itu
    adalah, jika tidak pernah terjadi bahwa Foo (tipe yang mengandung) adalah Unpin sementara
    Bar (jenis yang diproyeksikan) bukan Unpin .
  2. Ini hanya aman jika Bar tidak pernah dipindahkan selama penghancuran Foo ,
    artinya Foo tidak memiliki destruktor, atau destruktornya hati-hati
    diperiksa untuk memastikan tidak pernah keluar dari bidang yang diproyeksikan.
  3. Ini hanya aman jika Foo (tipe yang memuat) bukan repr(packed) ,
    karena hal ini menyebabkan bidang dipindahkan untuk menyetel kembali.

Selain itu, std API tidak menyediakan cara yang aman untuk menyematkan objek ke tumpukan.
Ini karena tidak ada cara untuk mengimplementasikannya dengan aman menggunakan API fungsi.
Namun, pengguna dapat memasang pin secara tidak aman ke tumpukan dengan menjaminnya
jangan pernah memindahkan objek lagi setelah membuat referensi yang disematkan.

pin-utils peti di crates.io berisi makro untuk membantu dengan kedua tumpukan
pinning dan proyeksi pin. Makro penyematan tumpukan dengan aman menyematkan objek ke
tumpukan menggunakan trik yang melibatkan bayangan, sedangkan makro untuk proyeksi ada
yang tidak aman, tetapi menghindari Anda harus menulis boilerplate proyeksi
yang mungkin bisa Anda masukkan kode tidak aman yang salah lainnya.

Implementasi berubah sebelum stabilisasi

  • [] Ekspor Unpin dari awal, hapus pin::Unpin ekspor ulang

Sebagai aturan umum, kami tidak mengekspor ulang sesuatu dari banyak tempat di std kecuali
satu adalah supermodul dari definisi sebenarnya (mis. pemendekan
std::collections::hash_map::HashMap hingga std::collections::HashMap ). Untuk ini
alasannya, ekspor ulang std::marker::Unpin dari std::pin::Unpin telah habis
tempat.

Pada saat yang sama, ciri penanda penting lainnya seperti Kirim dan Sinkronisasi disertakan
di awal. Jadi, alih-alih mengekspor ulang Unpin dari modul pin , oleh
dengan memasukkan awal kita membuatnya tidak perlu untuk mengimpor std::marker::Unpin ,
alasan yang sama itu dimasukkan ke dalam pin .

  • [] Ubah fungsi terkait ke metode

Saat ini, banyak fungsi terkait dari Pin tidak menggunakan sintaks metode.
Secara teori, ini untuk menghindari konflik dengan metode batin yang dapat dipercaya. Namun,
aturan ini belum diterapkan secara konsisten, dan sebagian besar menurut pengalaman kami
hanya membuat segalanya menjadi lebih tidak nyaman. Pointer yang dipasangi pin hanya menerapkan immutable
deref, bukan deref yang bisa berubah atau deref berdasarkan nilai, membatasi kemampuan untuk melakukan deref
bagaimanapun. Selain itu, banyak dari nama ini cukup unik (mis. map_unchecked )
dan tidak mungkin konflik.

Sebagai gantinya, kami lebih memilih untuk memberikan metode Pin prioritas mereka; pengguna yang
perlu mengakses metode interior selalu dapat menggunakan UFCS, seperti yang akan mereka lakukan
diperlukan untuk mengakses metode Pin jika kami tidak menggunakan sintaks metode.

  • [] Ubah nama get_mut_unchecked menjadi get_unchecked_mut

Pengurutan saat ini tidak konsisten dengan penggunaan lain di pustaka standar.

  • [] Hapus impl<P> Unpin for Pin<P>

Implikasi ini tidak dibenarkan oleh pembenaran standar kami untuk unpin impls: tidak ada arah penunjuk antara Pin<P> dan P . Kegunaannya tercakup dalam impls for pointers itu sendiri.

Implikasi masa depan ini perlu diubah untuk menambahkan P: Unpin terikat.

  • [] Tandai Pin sebagai repr(transparent)

Pin harus berupa pembungkus transparan di sekitar penunjuk di dalamnya, dengan representasi yang sama.

Fitur yang terhubung dan pencapaian yang lebih besar

API pin penting untuk memanipulasi bagian memori dengan aman
dijamin tidak akan dipindahkan. Jika objek dalam memori itu tidak
menerapkan Unpin , alamat mereka tidak akan pernah berubah. Ini diperlukan untuk
membuat generator referensi sendiri dan fungsi asynchronous. Hasil dari,
tipe Pin muncul di pustaka standar future API dan akan segera
muncul di API untuk generator juga (# 55704).

Menstabilkan tipe Pin dan API-nya merupakan prekursor yang diperlukan untuk menstabilkan
API Future , yang merupakan prekursor yang diperlukan untuk menstabilkan
async/await sintaks dan memindahkan seluruh ekosistem IO futures 0.3 async
ke Rust yang stabil.

cc @cramertj @RalfJung

T-libs finished-final-comment-period

Komentar yang paling membantu

Apakah seseorang ingin menulis bab nomicon tentang masa depan? Tampaknya sangat penting mengingat betapa halusnya hal ini. Secara khusus saya pikir contoh, terutama contoh implementasi buggy / buruk dan bagaimana mereka tidak sehat, akan mencerahkan.

Semua 213 komentar

@rachmuhammadfc gabung

Anggota tim @withoutboats telah mengusulkan untuk menggabungkan ini. Langkah selanjutnya adalah meninjau oleh anggota tim yang diberi tag lainnya:

  • [x] @kimundi
  • [] @SimonSapin
  • [x] @alexcrichton
  • [x] @dtolnay
  • [] @sfackler
  • [x] @withoutboats

Kekhawatiran:

  • box-pinnned-vs-box-pin (https://github.com/rust-lang/rust/issues/55766#issuecomment-443371976)
  • memperbaiki-dokumentasi (https://github.com/rust-lang/rust/issues/55766#issuecomment-443367737)
  • penamaan-dari-Unpin diselesaikan dengan https://github.com/rust-lang/rust/issues/55766#issuecomment -445074980
  • metode mandiri (https://github.com/rust-lang/rust/issues/55766#issuecomment-443368794)

Setelah mayoritas peninjau menyetujui (dan paling banyak 2 persetujuan masih berlaku), ini akan memasuki periode komentar terakhir. Jika Anda melihat masalah besar yang belum pernah diangkat dalam proses ini, silakan angkat bicara!

Lihat dokumen ini untuk info tentang perintah yang dapat diberikan anggota tim kepada saya.

Terima kasih untuk tulisan mendetail di sini @withoutboats! Saya juga agak bingung secara historis dengan berbagai jaminan Pin , dan saat ini saya punya beberapa pertanyaan tentang API yang distabilkan di sini tentang jaminan keamanan. Untuk membantu menyelesaikan masalah ini di kepala saya sendiri meskipun saya pikir saya akan mencoba menuliskan hal-hal ini.

Dalam mencoba untuk mulai menulis ini meskipun saya terus berlari ke dinding "apa Unpin ?" Saya agak bingung dengan apa itu dan berbagai jaminan di sekitarnya. Dapatkah Anda mengatakan lagi apa artinya T dan juga tidak menerapkan Unpin ? Juga, jika Unpin adalah sifat yang aman untuk menerapkannya secara naif, sepertinya itu dapat digunakan untuk dengan mudah merusak jaminan tidak aman dari Pin<T> , tetapi saya pasti melewatkan sesuatu

jika saya sudah mendapatkan ini dengan benar, setiap jenis yang bukan referensi sendiri (yaitu: bukan generator) adalah Lepas pin

Ini bukan hanya referensi diri, ada beberapa kasus penggunaan lain untuk alamat memori stabil yang juga dapat didukung oleh Pin . Mereka relatif sedikit dan jarang.

Bagaimana saya memahami Unpin aman untuk diterapkan adalah bahwa dengan menerapkannya Anda mungkin melanggar invarian yang diperlukan dari kode tidak aman lainnya yang telah Anda tulis (yang terpenting, hanya Anda yang dapat menulis kode tidak aman ini, tidak ada kode eksternal yang dapat bergantung pada apakah Anda telah menerapkan Unpin ). Tidak ada yang dapat Anda lakukan dengan API aman Pin yang akan menyebabkan ketidaknyamanan apakah Anda telah mengimplementasikan Unpin . Dengan memilih untuk menggunakan beberapa API yang tidak aman Pin Anda menjamin bahwa Anda hanya akan menerapkan Unpin jika aman untuk melakukannya. Itu tercakup dalam poin 1 dari bagian "Catatan tentang penyematan & keamanan" di atas.

Hm saya masih belum begitu mengerti Unpin . Pada awalnya saya hanya mencoba untuk memahami apa artinya menerapkan atau tidak menerapkan Unpin .

Pertama, mungkin berguna untuk mengetahui jenis apa yang menerapkan Unpin secara otomatis! Disebutkan di atas bahwa jenis penunjuk umum (Arc / Rc / Box / referensi) mengimplementasikan Unpin , tapi saya pikir hanya itu? Jika ini adalah sifat otomatis, apakah itu berarti bahwa tipe MyType secara otomatis mengimplementasikan Unpin jika hanya berisi pointer? Atau apakah tidak ada tipe lain yang secara otomatis menerapkan Unpin ?

Saya terus mencoba untuk meringkas atau menyatakan apa jaminan Unpin dan semacamnya, tetapi saya merasa sangat sulit untuk melakukannya. Dapatkah seseorang membantu dengan mengulangi lagi apa artinya menerapkan Unpin serta apa artinya tidak menerapkan Unpin ?

Saya rasa saya memahami jaminan Pin<P> mana Anda tidak dapat keluar dari salah satu anggota inline P::Target , tetapi apakah itu benar?

@alexcrichton Terima kasih atas pertanyaannya, saya yakin API

Pertama, mungkin berguna untuk mengetahui jenis apa yang menerapkan Lepas pin secara otomatis!

Lepas pin adalah sifat otomatis seperti Kirim atau Sinkronkan, jadi sebagian besar jenis menerapkannya secara otomatis. Generator dan jenis fungsi asinkron adalah !Unpin . Tipe yang bisa berisi generator atau badan fungsi async (dengan kata lain, tipe dengan parameter tipe) juga tidak otomatis Unpin kecuali parameter tipe mereka adalah.

Implikasi eksplisit untuk tipe pointer adalah membuat Unpin meskipun parameter tipenya tidak. Alasan untuk ini semoga akan lebih jelas pada akhir komentar ini.

Dapatkah seseorang membantu dengan mengulangi lagi apa artinya mengimplementasikan Lepas Pin serta apa artinya tidak menerapkan Lepas Pin?

Berikut adalah ide dasar dari pinning API. Pertama, diberikan tipe pointer P , Pin<P> bertindak seperti P kecuali jika P::Target mengimplementasikan Unpin , tidak aman untuk mengubah referensi Pin<P> . Kedua, ada dua kode tidak aman invarian dasar yang terkait dengan Pin harus dipelihara:

  • Jika Anda secara tidak aman mendapatkan &mut P::Target dari Pin<P> , Anda tidak boleh memindahkan P::Target .
  • Jika Anda dapat membuat Pin<P> , harus dijamin bahwa Anda tidak akan pernah bisa mendapatkan pointer yang tidak disematkan ke data yang ditunjuk oleh pointer sampai destruktor berjalan.

Implikasi dari semua ini adalah bahwa jika Anda membuat Pin<P> , nilai yang ditunjukkan oleh P tidak akan pernah bergerak lagi, yang merupakan jaminan yang kami butuhkan untuk struct referensi sendiri dan juga mengganggu. koleksi. Tetapi Anda dapat memilih keluar dari jaminan ini hanya dengan menerapkan Unpin untuk tipe Anda.

Jadi jika Anda menerapkan Unpin untuk suatu tipe, Anda mengatakan bahwa tipe tersebut memilih keluar dari jaminan keamanan tambahan sebesar Pin - mungkin untuk saling membedakan petunjuk yang menunjuk ke sana. Ini berarti Anda mengatakan bahwa tipe tidak perlu tidak bergerak untuk digunakan dengan aman.

Memindahkan tipe pointer seperti Rc<T> tidak akan memindahkan T karena T berada di belakang pointer. Demikian pula, menyematkan pointer ke Rc<T> (seperti dalam Pin<Box<Rc<T>> ) sebenarnya tidak menyematkan T , itu hanya menyematkan pointer tertentu. Inilah sebabnya mengapa apapun yang menyimpan generiknya di belakang pointer dapat mengimplementasikan Unpin bahkan ketika obat generik mereka tidak.

Juga, jika Lepas Pin adalah sifat yang aman untuk menerapkannya secara naif, sepertinya itu dapat digunakan untuk dengan mudah merusak jaminan Pin yang tidak aman., tapi aku pasti melewatkan sesuatu

Ini adalah salah satu bagian tersulit dari API pemasangan pin, dan kami salah pada awalnya.

Lepas pin berarti "bahkan setelah sesuatu dimasukkan ke dalam pin, aman untuk mendapatkan referensi yang bisa berubah ke pin itu." Ada ciri lain yang ada saat ini yang memberi Anda akses yang sama: Drop . Jadi apa yang kami temukan adalah karena Drop aman, Unpin juga harus aman. Apakah ini merusak seluruh sistem? Tidak terlalu.

Untuk benar-benar mengimplementasikan tipe referensi sendiri akan memerlukan kode yang tidak aman - dalam praktiknya, satu-satunya tipe referensi mandiri yang dipedulikan siapa pun adalah tipe yang dibuat oleh compiler untuk Anda: generator dan mesin status fungsi asinkron. Ini secara eksplisit mengatakan mereka tidak mengimplementasikan Unpin dan mereka tidak memiliki implementasi Drop , jadi Anda tahu, untuk tipe ini, setelah Anda memiliki Pin<&mut T> , mereka akan tidak pernah benar-benar mendapatkan referensi yang bisa berubah, karena mereka adalah tipe anonim yang kami tahu tidak menerapkan Lepas Pin atau Lepas.

Masalahnya muncul setelah Anda memiliki struct yang berisi salah satu dari jenis anonim ini, seperti kombinator masa depan. Untuk beralih dari Pin<&mut Fuse<Fut>> menjadi Pin<&mut Fut> , Anda harus melakukan "proyeksi pin". Di sinilah Anda dapat mengalami masalah: jika Anda menyematkan proyek ke bidang kombinator di masa mendatang, tetapi kemudian menerapkan Jatuhkan untuk kombinator, Anda dapat keluar dari bidang yang seharusnya disematkan.

Karena alasan ini, proyeksi pin tidak aman! Untuk melakukan proyeksi pin tanpa melanggar invarian pin, Anda harus menjamin bahwa Anda tidak pernah melakukan beberapa hal, yang saya cantumkan dalam proposal stabilisasi.

Jadi, tl; dr: Drop ada, jadi Unpin pasti aman. Tetapi ini tidak merusak semuanya, itu hanya berarti bahwa proyeksi pin adalah unsafe dan siapa pun yang ingin memasang pin pada proyek perlu mempertahankan satu set invarian.

generator dan mesin status fungsi async. Ini secara eksplisit mengatakan bahwa mereka tidak mengimplementasikan Lepas Pin dan tidak memiliki implementasi Jatuhkan, jadi Anda tahu, untuk jenis ini, setelah Anda memiliki Pin <& mut T>, mereka tidak akan pernah benar-benar mendapatkan referensi yang bisa berubah, karena mereka jenis anonim yang kami tahu tidak menerapkan Lepas Pin atau Lepas.

Bukankah mesin status async memiliki implementasi Drop ? Hal-hal yang ada di "tumpukan" dari fungsi asinkron (yang mungkin sama dengan bidang di mesin status) perlu dihancurkan ketika fungsi asinkron selesai atau dibatalkan. Atau apakah ini terjadi sebaliknya?

Saya rasa yang penting dalam konteks ini adalah apakah item impl Drop for Foo {…} ada, yang akan menjalankan kode dengan &mut Foo yang dapat digunakan misalnya mem::replace untuk "exfiltrate" dan memindahkan Foo nilai.

Ini tidak sama dengan "lem jatuh", yang dapat disebut melalui ptr::drop_in_place . Lem tetes untuk tipe Foo akan memanggil Drop::drop jika diimplementasikan, kemudian secara rekursif memanggil lem tetes untuk setiap bidang. Tetapi panggilan rekursif itu tidak pernah melibatkan &mut Foo .

Selain itu, sementara generator (dan karenanya mesin status asinkron) memiliki lem drop kustom, itu hanya untuk menjatuhkan kumpulan bidang yang benar berdasarkan keadaan saat ini, ia berjanji untuk tidak pernah memindahkan bidang apa pun selama penurunan.

Terminologi yang saya gunakan (meskipun saya tidak berpikir ada standar apa pun): "lem jatuh" adalah kompiler yang dihasilkan berjalannya bidang rekursif, memanggil destruktornya; "Implementasi Jatuhkan" adalah implementasi dari sifat Drop , dan "destruktor" adalah kombinasi dari lem jatuh dan implementasi Jatuhkan. Lem drop tidak pernah memindahkan apapun, jadi kami hanya peduli tentang implementasi Drop.

Apakah seseorang ingin menulis bab nomicon tentang masa depan? Tampaknya sangat penting mengingat betapa halusnya hal ini. Secara khusus saya pikir contoh, terutama contoh implementasi buggy / buruk dan bagaimana mereka tidak sehat, akan mencerahkan.

@Gankro Tentu, Anda bisa menurunkan saya untuk itu.

Terima kasih atas penjelasannya semuanya!

Saya pribadi sangat baru dalam async Rust dan Pin API, tapi saya telah bermain-main dengannya selama beberapa hari terakhir (https://github.com/rust-lang-nursery/futures-rs/pull/1315 - di mana Saya mencoba mengeksploitasi pinning untuk koleksi yang mengganggu dalam kode async).

Selama percobaan, saya mendapat beberapa masalah dengan API ini:

  • Konsep penyematan tampaknya sangat sulit untuk dipahami sepenuhnya, bahkan jika seseorang mengetahui bahwa alamat memori yang stabil diperlukan. Beberapa tantangan yang saya hadapi:

    • Pesan kesalahan seperti:

      > dalam impl core::future::future::Future+futures_core::future::FusedFuture , ciri std::marker::Unpin tidak diterapkan untuk std::marker::Pinned

      Yang ini terdengar sangat rekursif dan kontradiktif (mengapa sesuatu yang disematkan tidak disematkan?)

    • Bagaimana saya bisa mengakses bidang yang bisa berubah dalam metode saya yang menggunakan Pin sebagai parameter. Butuh sedikit pencarian, mempelajari istilah baru ( Pin proyeksi), mencoba menyalin metode dari pin-utils , sampai saya menemukan solusi yang menggunakan 2 metode tidak aman untuk melakukan apa yang saya butuhkan .

    • Bagaimana sebenarnya saya bisa menggunakan masa depan saya dalam metode async dan kasus select . Ternyata saya perlu pin_mut!() itu untuk tumpukan berjangka. Yang sebenarnya bukan tumpukan, yang membuatnya membingungkan.

    • Mengapa metode drop() sekarang lagi mengambil &mut self , bukan Pin .

    • Secara keseluruhan, itu adalah sedikit perasaan secara acak menggunakan API terkait pin yang tidak aman dengan harapan mendapatkan hal-hal untuk dikompilasi, yang pastinya seharusnya tidak menjadi situasi yang ideal. Saya curiga orang lain mungkin mencoba melakukan hal serupa.

  • Konsep ini banyak menyebar ke seluruh basis kode, yang tampaknya memaksa banyak orang untuk memahami apa sebenarnya Pin dan Unpin . Ini sepertinya merupakan kebocoran detail implementasi untuk beberapa kasus penggunaan yang lebih khusus.
  • Pin tampaknya agak terkait dengan masa hidup, tetapi juga agak ortogonal. Pada dasarnya Pin memberi tahu kita bahwa kita mungkin melihat objek lagi dengan alamat yang persis sama sampai drop() dipanggil. Yang memberinya semacam masa virtual antara cakupan saat ini dan 'static . Tampaknya membingungkan memiliki 2 konsep yang saling terkait, tetapi masih sangat berbeda. Saya bertanya-tanya apakah itu dapat dimodelkan dengan sesuatu seperti 'pinned .

Saat mendapatkan sesuatu untuk dikompilasi, saya sering memikirkan tentang C ++, di mana sebagian besar masalah ini dihindari: Jenis dapat dinyatakan tidak dapat dipindahkan dengan menghapus konstruktor pemindahan dan operator penugasan. Ketika sebuah tipe tidak bisa dipindahkan, tipe yang berisi tipe itu juga tidak. Dengan demikian properti dan persyaratan mengalir secara native melalui hierarki tipe dan diperiksa oleh compiler, daripada meneruskan properti di dalam beberapa panggilan (tidak semua, misalnya bukan drop() ). Saya pikir ini jauh lebih mudah untuk dipahami. Tapi mungkin tidak berlaku untuk Rust, karena Future s saat ini harus sering dipindahkan sebelum sesuatu mulai melakukan polling? Tapi di sisi lain itu mungkin bisa diperbaiki dengan definisi baru dengan sifat itu, atau memisahkan fase perpindahan dan polling.

Mengenai Alex Unpin komentar: Saya perlahan-lahan memahami apa artinya Unpin , tetapi saya setuju bahwa itu sulit untuk dipahami. Mungkin nama lain bisa membantu, tapi saya tidak bisa menemukan yang ringkas sekarang. Sesuatu ThingsInsideDontBreakIfObjectGetsMoved , DoesntRequireStableAddress , PinDoesntMatter , dll.

Apa yang belum sepenuhnya saya pahami adalah, mengapa mendapatkan &mut self dari Pin<&mut self> tidak aman untuk semua jenis. Jika Pin hanya berarti alamat objek itu sendiri stabil, maka ini harus berlaku untuk sebagian besar tipe Rust. Tampaknya ada masalah lain yang diintegrasikan ke dalam Pin, yaitu bahwa tipe referensi mandiri di dalamnya tidak rusak. Untuk tipe yang memanipulasi mereka setelah memiliki Pin selalu tidak aman. Tapi saya pikir dalam banyak kasus itu akan dihasilkan oleh kompiler, dan tidak aman atau bahkan petunjuk mentah seharusnya baik-baik saja. Untuk kombinator masa depan secara manual yang perlu meneruskan panggilan yang disematkan ke subbidang, jelas perlu ada panggilan tidak aman untuk membuat pin ke bidang sebelum melakukan polling. Tetapi dalam kasus itu saya melihat ketidakamanan lebih terkait dengan tempat yang sebenarnya penting (apakah pin masih valid?) Daripada mengakses bidang lain yang tidak menjadi masalah sama sekali.

Pemikiran lain yang saya miliki adalah apakah mungkin untuk mendapatkan sistem yang lebih sederhana jika beberapa batasan diterapkan. Misalnya jika hal-hal yang memerlukan penyematan hanya dapat digunakan di dalam metode asinkron dan tidak dengan kombinator masa depan. Mungkin itu bisa menyederhanakan sesuatu menjadi salah satu dari Pin atau Unpin . Mempertimbangkan bahwa untuk banyak metode kode async / await dengan dukungan pilih / gabung mungkin menguntungkan bagi kombinator, ini mungkin bukan kerugian terbesar. Tetapi saya belum cukup memikirkan apakah ini benar-benar membantu.

Sisi positifnya: Mampu menulis kode async / await dengan pinjaman "stack" cukup keren dan sangat dibutuhkan! Dan kemampuan untuk menggunakan pemasangan pin untuk kasus penggunaan lain, seperti koleksi yang mengganggu, akan membantu performa serta target seperti sistem atau kernel yang disematkan. Jadi saya sangat menantikan solusi untuk ini.

Sedikit nit wrt laporan stabilisasi:

fn get_unchecked_mut(self) -> &'a mut T

Saya menduga ini sebenarnya adalah unsafe fn ?

@ Matthias247 Anda tidak dapat dengan aman mendapatkan & mut T dari Pin<P<T>> jika T bukan Lepas pin karena Anda dapat mem::swap untuk mengeluarkan T dari Pin, yang akan menggagalkan tujuan menyematkan sesuatu.

Satu hal yang sulit saya jelaskan kepada diri saya sendiri adalah apa yang membuat Future berbeda secara fundamental dari ciri-ciri lain sehingga Pin perlu menjadi bagian dari API-nya. Maksud saya, saya tahu secara intuitif itu karena async / await memerlukan penyematan, tetapi apakah itu menjelaskan secara spesifik tentang Futures yang berbeda dari, katakanlah, Iterator?

Bisakah jajak pendapat mengambil & mut sendiri dan hanya menerapkan Future untuk jenis Pin<P> atau jenis yang Lepas pin?

Bagaimana saya bisa mengakses bidang yang bisa berubah dalam metode saya yang menggunakan Pin sebagai parameter.

Ini benar-benar membuat saya bertanya-tanya apakah ada beberapa metode yang hilang pada Pin ,

impl<'a, T: ?Sized> Pin<&'a T> {
    fn map<U: Unpin, F: FnOnce(&T) -> &U>(self, f: F) -> Pin<&'a U>
}

impl<'a, T: ?Sized> Pin<&'a mut T> {
    fn map<U: Unpin, F: FnOnce(&mut T) -> &mut U>(self, f: F) -> Pin<&'a mut U>
}

Ini dapat digunakan di makro pin_utils::unsafe_unpinned! .

Saya mencoba mencari _mengapa_ makro ini mengklaim tidak aman. Jika kami !Unpin dan memiliki bidang Unpin , mengapa tidak aman untuk memproyeksikan bidang ini?

Satu-satunya situasi di mana saya dapat melihatnya tidak sehat adalah mengimplementasikan tipe kustom !Unpin , mengambil pointer mentah ke bidang Unpin diri (dan mengandalkannya memiliki alamat yang stabil / menunjuk ke instance yang sama), lalu memperoleh &mut ke bidang yang sama dan meneruskannya ke fungsi eksternal. Ini tampaknya berada di bawah alasan yang sama mengapa menerapkan Unpin itu aman, dengan mengambil pointer mentah ke bidang !Unpin Anda memilih untuk tidak dapat memanggil beberapa brankas Lebah.

Untuk membuat situasi sebelumnya lebih aman mungkin ada pembungkus yang dibangun di atas Pinned untuk menandai yang biasanya Unpin bidang struct sebenarnya !Unpin daripada hanya menambahkan Pinned ke struct secara keseluruhan:

pub struct MustPin<T: Unpin>(T, Pinned);

impl<T: Unpin> MustPin<T> {
    pub const fn new(t: T) -> Self { ... }
    pub fn get(self: Pin<&Self>) -> *const T { ... }
    pub fn get_mut(self: Pin<&mut Self>) -> *mut T { ... }
}

Ini semua tampaknya kompatibel dengan API saat ini, ini dapat menghapus beberapa ketidakamanan dari futures-rs combinators (misalnya akan memberikan akses yang aman ke bidang tambahan seperti ini ), tetapi tidak diperlukan untuk penggunaan saat ini. Kami mungkin dapat bereksperimen dengan beberapa API seperti ini untuk menerapkan jenis !Unpin (seperti koleksi yang mengganggu) dan menambahkannya nanti.

@ Nemo157 Fungsi peta tersebut tidak aman karena saya bisa mem::swap pada &mut T fungsi melewati saya sebelum mengembalikan &mut U . (baik yang bisa berubah adalah, yang tidak bisa diubah mungkin tidak aman)

EDIT: Juga makro pin-utils berbeda, unsafe_unpinned tidak ada hubungannya dengan tipe target menjadi Unpin , ini hanya sebuah "proyeksi yang tidak disematkan" - proyeksi ke &mut Field . Ini aman digunakan selama Anda tidak pernah menyematkan proyek ke bidang itu, meskipun bidang itu !Unpin .

Satu hal yang sulit saya jelaskan kepada diri saya sendiri adalah apa yang membuat Future berbeda secara fundamental dari ciri-ciri lain sehingga Pin perlu menjadi bagian dari API-nya. Maksud saya, saya tahu secara intuitif itu karena async / await memerlukan penyematan, tetapi apakah itu menjelaskan secara spesifik tentang Futures yang berbeda dari, katakanlah, Iterator?

Tidak ada perbedaan teoretis, tetapi ada yang pragmatis. Pertama, Iterator stabil. Tetapi sebagai hasilnya, kecuali kita menemukan sesuatu yang sangat pintar, Anda tidak akan pernah bisa menjalankan loop for melalui generator referensi sendiri tanpa tipuan ganda, meskipun itu seharusnya aman sepenuhnya tanpanya ( karena loop for akan mengkonsumsi dan tidak pernah menggerakkan generator).

Perbedaan pragmatis penting lainnya adalah bahwa pola kode antara Iterator dan Future sangat berbeda. Anda tidak dapat pergi 10 menit tanpa ingin meminjam melintasi menunggu titik di masa depan, itulah sebabnya di futures 0.1 Anda melihat Arc s ini muncul di semua tempat sehingga Anda dapat menggunakan variabel yang sama dalam dua yang berbeda and_then panggilan. Tapi kita sudah cukup jauh tanpa bisa mengekspresikan iterator referensi sendiri sama sekali, hanya saja kasus penggunaan tidak terlalu penting.

Fungsi peta tersebut tidak aman karena saya bisa mem::swap pada &mut T fungsi melewati saya sebelum mengembalikan &mut U

Ah, sial, lupakan bagian itu: cemberut:

fn as_mut(&mut self) -> Pin<&mut P::Target> fn into_ref (self) -> Pin <& 'a T> `

Haruskah ini disebut as_pinned_mut dan into_pinned_ref , untuk menghindari kebingungan mereka dengan metode yang sebenarnya mengembalikan referensi?

Implementasi penting dari Lepas Pin di std:

Kami juga memiliki impl<P> Unpin for Pin<P> {} . Untuk tipe yang kita gunakan ini tidak berpengaruh dan sepertinya sedikit lebih aman?
Tidak apa-apa, Anda memiliki itu di daftar Anda. ;)

Jatuhkan jaminan

Saya pikir kita harus mengkodifikasi jaminan Drop sebelum stabilisasi, atau akan terlambat:

Adalah ilegal untuk membatalkan penyimpanan objek yang disematkan (target referensi Pin ) tanpa memanggil drop pada objek.

"Invalidate" di sini bisa berarti "deallocation", tetapi juga "repurposing": Saat mengubah x dari Ok(foo) menjadi Err(bar) , penyimpanan foo menjadi tidak valid .

Ini memiliki konsekuensi, misalnya, membatalkan alokasi Pin<Box<T>> , Pin<Rc<T>> atau Pin<Arc<T>> menjadi ilegal tanpa terlebih dahulu memanggil drop::<T> .

Menggunakan kembali Deref , DerefMut

Saya masih merasa sedikit tidak nyaman tentang bagaimana ini mengganti sifat Deref menjadi "ini adalah penunjuk yang cerdas". Kami juga menggunakan Deref untuk hal-hal lain, misalnya untuk "warisan". Itu mungkin anti-pola, tapi masih cukup umum digunakan dan, terus terang, itu berguna. : D

Saya pikir ini bukan masalah kesehatan.

Memahami Unpin

Steker tak tahu malu: Saya menulis dua posting blog tentang ini, yang mungkin membantu atau tidak tergantung pada seberapa senang Anda membaca sintaks (semi-) formal. ;) API telah berubah sejak saat itu, tetapi ide dasarnya belum.

Proyeksi pin aman

@ Matthias247 Saya rasa satu masalah yang Anda hadapi adalah bahwa membangun abstraksi yang melibatkan penyematan saat ini hampir selalu membutuhkan kode yang tidak aman. Menggunakan abstraksi itu baik-baik saja, tetapi misalnya, mendefinisikan kombinator masa depan dalam kode aman tidak akan berhasil. Alasannya adalah karena "proyeksi pin" memiliki batasan yang hanya dapat kami periksa dengan aman dengan perubahan kompilator. Misalnya, Anda bertanya

Mengapa metode drop () saya sekarang mengambil & mut self lagi, bukan Pin.

Nah, drop() sudah tua - sudah ada sejak Rust 1.0 - jadi kita tidak bisa mengubahnya. Kami ingin sekali membuatnya mengambil Pin<&mut Self> , dan kemudian tipe Unpin bisa mendapatkan &mut seperti yang mereka lakukan sekarang, tapi itu adalah perubahan yang tidak kompatibel ke belakang.

Untuk membuat penulisan kombinator masa depan aman, kita memerlukan proyeksi pin yang aman, dan untuk itu kita harus mengubah kompiler, ini tidak dapat dilakukan di perpustakaan. Kita hampir bisa melakukannya di derive proc_macro, kecuali kita membutuhkan cara untuk menyatakan "tipe ini tidak memiliki implementasi Drop atau Unpin ".

Saya pikir akan sepadan dengan usaha untuk mencari tahu bagaimana mendapatkan API yang aman untuk proyeksi pin. Namun, itu tidak harus menghalangi stabilisasi: API yang kami stabilkan di sini harus kompatibel dengan proyeksi pin yang aman. ( Unpin mungkin harus menjadi item lang untuk mengimplementasikan pernyataan di atas, tapi sepertinya tidak terlalu buruk.)

Menjepit tidak! Move

Saya sering berpikir tentang C ++, di mana sebagian besar masalah ini dihindari: Jenis dapat dinyatakan tidak dapat dipindahkan dengan menghapus konstruktor pemindahan dan operator penugasan. Ketika sebuah tipe tidak bisa dipindahkan, tipe yang berisi tipe itu juga tidak.

Ada beberapa upaya untuk menentukan tipe yang tidak dapat dipindahkan untuk Rust. Ini menjadi sangat rumit dengan sangat cepat.

Satu hal penting untuk dipahami adalah bahwa pemasangan pin tidak menyediakan tipe yang T , Anda dapat memindahkannya ke mana pun Anda mau. Alih-alih tipe yang tidak dapat dipindahkan , kami menggunakan kemampuan Rust untuk mendefinisikan API baru yang dienkapsulasi, karena kami mendefinisikan Pin<&mut T> ), bukan di pointee ( T ). Tidak ada cara bagi tipe untuk mengatakan "Saya tidak bisa dipindahkan selamanya". Namun, ada cara untuk jenis untuk mengatakan "Jika aku disematkan, tidak bergerak lagi". Jadi MyFuture yang saya miliki akan selalu dapat dipindahkan, tetapi Pin<&mut MyFuture> adalah penunjuk ke instance MyFuture yang tidak dapat dipindahkan lagi .

Ini adalah poin yang halus, dan kita mungkin harus meluangkan waktu untuk menyempurnakan dokumen di sini untuk membantu menghindari kesalahpahaman yang sangat umum ini.

Tapi kita sudah cukup jauh tanpa bisa mengekspresikan iterator referensi sendiri sama sekali, hanya saja kasus penggunaan tidak terlalu penting.

Ini karena, sejauh ini, semua iterator ditentukan menggunakan tipe dan blok impl Iterator for … . Ketika status perlu disimpan di antara dua iterasi, tidak ada pilihan selain menyimpannya di bidang tipe iterator dan bekerja dengan &mut self .

Namun, meskipun ini bukan motivasi utama untuk menyertakan generator dalam bahasa, alangkah baiknya jika pada akhirnya dapat menggunakan generator yield sintaks untuk mendefinisikan sesuatu yang dapat digunakan dengan for loop. Segera setelah itu ada, meminjam yield karena sama pentingnya untuk generator-iterator seperti halnya generator-futures.

( Unpin mungkin harus menjadi item lang untuk mengimplementasikan pernyataan di atas, tapi sepertinya tidak terlalu buruk.)

Unpin dan Pin sudah harus menjadi item lang untuk mendukung generator tak bergerak yang aman.

Ok terima kasih atas penjelasannya semua! Saya setuju dengan @Gankro bahwa bab bergaya nomicon tentang Pin dan semacamnya akan sangat berguna di sini. Saya menduga ada banyak riwayat pengembangan mengapa berbagai metode aman ada dan mengapa metode yang tidak aman tidak aman dan semacamnya.

Dalam upaya untuk membantu diri saya sendiri memahami hal ini meskipun saya ingin mencoba lagi untuk menuliskan mengapa setiap fungsi aman atau mengapa unsafe . Dengan pemahaman dari atas, saya mendapatkan semua yang berikut, tetapi ada beberapa pertanyaan di sana-sini. Jika orang lain dapat membantu saya mengisi ini, itu bagus! (atau bantu menunjukkan di mana pemikiran saya salah)

  • fn new(P) -> Pin<P> where P: Deref, P::Target: Unpin

    • Ini adalah metode yang aman untuk membangun Pin<P> , dan selama keberadaan
      Pin<P> biasanya berarti P::Target tidak akan pernah dipindahkan lagi di file
      program, P::Target mengimplementasikan Unpin yang dibaca "jaminan
      Pin tidak ada lagi ". Akibatnya, keamanan di sini adalah karena tidak ada
      jaminan untuk ditegakkan, jadi semuanya bisa berjalan seperti biasa.
  • unsafe fn new_unchecked(P) -> Pin<P> where P: Deref

    • Berbeda dengan sebelumnya, fungsi ini adalah unsafe karena P tidak
      perlu menerapkan Unpin , jadi Pin<P> harus menjunjung tinggi jaminan itu
      P::Target tidak akan pernah bergerak lagi setelah Pin<P> dibuat.

    Cara sepele untuk melanggar jaminan ini, jika fungsi ini aman, lihat
    Suka:

    fn foo<T>(mut a: T, b: T) {
        Pin::new_unchecked(&mut a); // should mean `a` can never move again
        let a2 = mem::replace(&mut a, b);
        // the address of `a` changed to `a2`'s stack slot
    }
    

    Akibatnya, terserah pengguna untuk menjamin bahwa Pin<P> memang berarti
    P::Target tidak pernah dipindahkan lagi setelah konstruksi, jadi unsafe !

  • fn as_ref(&Pin<P>) -> Pin<&P::Target> where P: Deref

    • Diberikan Pin<P> kami memiliki jaminan bahwa P::Target tidak akan pernah bergerak. Begitulah
      bagian dari kontrak Pin . Akibatnya hal itu berarti begitu
      &P::Target , "pointer pintar" lainnya ke P::Target akan memberikan hal yang sama
      dijamin, jadi &Pin<P> dapat dengan aman diterjemahkan ke Pin<&P::Target> .

    Ini adalah metode umum untuk beralih dari Pin<SmartPointer<T>> menjadi Pin<&T>

  • fn as_mut(&mut Pin<P>) -> Pin<&mut P::Target> where P: DerefMut

    • Saya percaya keamanan di sini kira-kira sama dengan as_ref atas.
      Kami tidak membagikan akses yang dapat diubah, hanya Pin , jadi tidak ada yang bisa dengan mudah
      dilanggar.

    Pertanyaan : bagaimana dengan DerefMut impl yang "jahat"? Ini adalah cara yang aman
    untuk memanggil DerefMut yang disediakan pengguna yang mengemas &mut P::Target secara asli,
    mungkin mengizinkannya untuk memodifikasinya juga. Bagaimana ini aman?

  • fn set(&mut Pin<P>, P::Target); where P: DerefMut

    • Pertanyaan : Diberikan Pin<P> (dan fakta bahwa kami tidak tahu apa-apa
      Unpin ), bukankah ini harus menjamin bahwa P::Target tidak pernah bergerak? Jika kita bisa
      menginisialisasi ulang dengan P::Target , bukankah ini tidak aman?
      Atau apakah ini terkait dengan destruktor dan semua itu?
  • unsafe fn map_unchecked<U, FnOnce(&T) -> &U>(Pin<&'a T>, f: F) -> Pin<&'a U>

    • Ini adalah fungsi unsafe jadi pertanyaan utama di sini adalah "mengapa bukan ini
      aman "? Contoh pelanggaran jaminan jika ini aman terlihat seperti:

    ...

    Pertanyaan :: apa contoh tandingannya di sini? Jika ini aman, apa
    contoh yang menunjukkan pelanggaran jaminan Pin ?

  • fn get_ref(Pin<&'a T>) -> &'a T

    • Jaminan Pin<&T> berarti T tidak akan pernah bergerak. Mengembalikan &T
      tidak mengizinkan mutasi T , jadi ini harus aman dilakukan sambil mempertahankan
      jaminan ini.

    Satu "mungkin gotcha" di sini adalah mutabilitas interior, bagaimana jika T
    RefCell<MyType> ? Ini, bagaimanapun, tidak melanggar jaminan
    Pin<&T> karena jaminan hanya berlaku untuk T secara keseluruhan, bukan
    bidang interior MyType . Sementara mutabilitas interior bisa berpindah-pindah
    internal, itu masih secara fundamental tidak dapat memindahkan seluruh struktur di belakang a
    & referensi.

  • fn into_ref(Pin<&'a mut T>) -> Pin<&'a T>

    • Pin<&mut T> berarti T tidak akan pernah bergerak. Hasilnya berarti Pin<&T>
      memberikan jaminan yang sama. Seharusnya tidak banyak masalah dengan konversi ini,
      itu kebanyakan beralih jenis.
  • unsafe fn get_unchecked_mut(Pin<&'a mut T>) -> &'a mut T

    • Pin<&mut T> berarti T tidak boleh berpindah, jadi ini sepele unsafe
      karena Anda dapat menggunakan mem::replace pada hasil untuk memindahkan T (dengan aman). Itu
      unsafe sini "meskipun saya memberi Anda &mut T , Anda tidak diizinkan untuk melakukannya
      pindahkan T ".
  • unsafe fn map_unchecked_mut<U, F: FnOnce(&mut T) -> &mut U>(Pin<&'a mut T>, f: F) -> Pin<&'a mut U>

    • Saya pikir unsafe sini pada dasarnya setidaknya sama seperti di atas, kami
      membagikan &mut T dengan aman (tidak memerlukan penutupan yang tidak aman) yang bisa
      mudah digunakan dengan mem::replace . Mungkin ada ketidakamanan lain di sini juga
      dengan proyeksi, tetapi tampaknya masuk akal bahwa itu setidaknya tidak aman
      karena itu.
  • fn get_mut(Pin<&'a mut T>) -> &'a mut T where T: Unpin

    • Dengan menerapkan Unpin sebuah tipe mengatakan " Pin<&mut T> tidak memiliki jaminan, itu
      hanya pembungkus tipe baru &mut T ". Akibatnya, tanpa jaminan untuk
      tegak, kita dapat mengembalikan &mut T dengan aman
  • impl<P: Deref> Deref for Pin<P> { type Target = P::Target }

    • Ini dapat diimplementasikan dengan aman dengan as_ref diikuti oleh get_ref , jadi
      keamanan impl ini mengikuti dari di atas.
  • impl<P: DerefMut> DerefMut for Pin<P> where T::Target: Unpin { }

    • Ini dapat diimplementasikan dengan aman dengan as_mut diikuti oleh get_mut , jadi
      keamanan impl ini mengikuti dari di atas.
  • impl<T: ?Sized> Unpin for Box<T> (dan implementasi terkait penunjuk lainnya)

    • Jika tidak ada tindakan lain yang diambil, Box<T> akan menerapkan sifat Unpin
      hanya jika T menerapkan Unpin . Implementasi ini di sini mengkodifikasi gen itu
      jika T secara eksplisit tidak mengimplementasikan Unpin , Box<T> mengimplementasikan Unpin .

    Pertanyaan : Apa contoh dari apa yang secara fundamental memberdayakan ini?

    Misalnya, apa yang aman bisa membutuhkan unsafe jika impl

    Tidak ada.


@ Matthias247 Anda tidak bisa mendapatkan & mut T dengan aman dari Pin

> jika T bukan Lepas pin karena Anda dapat mem :: swap untuk mengeluarkan T dari Pin, yang akan menggagalkan tujuan memasang pin.

Terima kasih! Ya, karena swap bukanlah metode yang tidak aman, ini jelas bermasalah. Tapi bisakah itu diperbaiki dengan menambahkan Unpin terikat ke swap() ? Karena semua kode hingga sekarang harus Unpin atau bagaimanapun juga tidak aman, ini seharusnya tidak merusak apa pun.

Saya kira salah satu hal yang paling membingungkan saya adalah bahwa Pin<T> mengkodifikasikan beberapa jaminan: Bahwa alamat T stabil, serta beberapa jaminan tentang keadaan internalnya (agak beku / tidak dapat diubah di beberapa situasi, tetapi juga tidak juga).

Bagi saya sepertinya memindahkan kode / proyeksi yang tidak aman hanya ke tempat-tempat di mana panggilan berbasis Pin lebih lanjut diperlukan (misalnya dalam poll s pada bidang) mungkin lebih baik untuk menangani proyeksi yang tidak aman tersebut di semua kasus. Namun sekarang saya juga menyadari bahwa ada masalah lain dengan itu: Kode yang memiliki akses ke referensi yang bisa berubah dapat memindahkan bidang dengan bebas, dan ketika drop() kemudian dipanggil dengan aman di bidang ini, itu mungkin rusak karena itu alamat disimpan di tempat lain. Untuk itu, diperlukan kelebihan drop(Pin<T>) yang dibicarakan.

@RalfJung Terima kasih atas penjelasannya! Saya setuju dengan fakta bahwa saya benar-benar mencoba melakukan sesuatu yang tidak aman secara umum, dan oleh karena itu tidak masalah untuk meminta pemahaman ekstra dari saya. Saya lebih khawatir tentang orang-orang yang ingin menulis kombinator masa depan yang lebih aman secara umum, tetapi sekarang juga mungkin dihadapkan pada semua istilah itu. Jika mereka dapat menulis kombinator tanpa harus memahami Unpin dan proyeksi pin sama sekali, dan kemudian hanya mendapatkan kombinator yang bekerja dengan cara yang lebih rendah (hanya pada Unpin futures), itu tampaknya lebih disukai. Karena saya belum mencobanya, saya tidak dapat mengatakan apakah saat ini masalahnya. Saya pikir seseorang masih perlu menambahkan setidaknya Unpin batas secara manual.

Saya juga memahami fakta bahwa jenis yang tidak dapat dipindahkan berbeda dari jenis pin. Namun saya saat ini lebih fokus pada kasus penggunaan daripada perbedaannya. Dan untuk kasus penggunaan koleksi yang mengganggu, tipe yang tidak dapat dipindahkan bekerja dengan sangat baik tanpa menimbulkan terlalu banyak kerumitan. Untuk masa depan jelas beberapa penelitian akan diperlukan, karena cara mereka dari jenis yang dapat dipindah ke jenis yang tidak dapat dipindah tidak ada. Jika cara itu tidak lebih ergonomis daripada Pin API, juga tidak akan ada kemenangan.

Menambahkan T: Unpin ke mem::swap berarti ini tidak dapat digunakan pada jenis tertentu meskipun mereka tidak berada di dalam Pin.

Tapi bisakah itu diperbaiki dengan menambahkan Unpin terikat ke swap ()? Karena semua kode hingga saat ini harus Lepas pin atau tetap tidak aman, tindakan ini tidak akan merusak apa pun.

Itu akan merusak semua kode generik: Jika Anda menulis fungsi di karat stabil hari ini untuk beberapa T tanpa batasan, Anda dapat memanggil swap di atasnya. Ini harus terus bekerja.

tipe non-moveable bekerja dengan sangat baik tanpa menimbulkan terlalu banyak kerumitan.

Tidak ada yang mendemonstrasikan cara untuk menambahkan jenis yang tidak dapat dipindahkan ke Rust dengan cara yang kompatibel dengan mundur tanpa kerumitan yang secara signifikan melebihi apa yang diusulkan untuk stabilisasi di sini. Anda harus menemukan beberapa proposal dan diskusi lama ini di repo RFC. Lihat https://github.com/rust-lang/rfcs/pull/1858 untuk satu contoh.

RFC di https://github.com/rust-lang/rfcs/pull/2349 serta seri blog boat yang dimulai di sini akan membantu memberi Anda beberapa latar belakang dan kesan dari desain lain yang dipertimbangkan. (Perhatikan juga tanggalnya, desain ini telah dikerjakan selama hampir 10 bulan!)

Juga mem :: swap adalah ikan haring merah, karena sama sekali bukan fungsi yang menarik. Benar-benar adil

let temp = *a; 
*a = *b; 
*b = temp;

@Gankro tidak menggunakan kode yang tidak aman? Afaik tidak mungkin menulisnya secara harfiah.

Sunting: Saya kira cara lain untuk berpikir tentang ini adalah menambahkan T: Unpin ke mem::swap sebenarnya mengubah definisi keamanan di tingkat bahasa. Itu akan menghancurkan semua mycrate::swap fns di alam liar.

Menambahkan T: Lepas pin ke mem :: swap berarti ini tidak dapat digunakan pada jenis tertentu meskipun mereka tidak berada di dalam Pin.

Jika Lepas pin secara otomatis diturunkan (dengan cara yang sama seperti Sync / Send adalah) maka saya pikir ini seharusnya tidak menjadi masalah.

Itu akan merusak semua kode generik: Jika Anda menulis sebuah fungsi di karat stabil hari ini untuk beberapa T tanpa batasan, Anda dapat memanggil swap di atasnya. Ini harus terus bekerja.

Tapi yang ini jelas sekali. Tidak memikirkan fakta bahwa batas sifat perlu disebarkan secara eksplisit di Rust.

Tidak ada yang telah mendemonstrasikan cara untuk menambahkan jenis yang tidak dapat dipindahkan ke Rust dengan cara yang kompatibel ke belakang tanpa kerumitan yang secara signifikan melebihi apa yang diusulkan untuk stabilisasi di sini. Anda harus menemukan beberapa proposal dan diskusi lama ini di repo RFC. Lihat rust-lang / rfcs # 1858 untuk satu contoh.

Terima kasih, saya akan membaca sedikit lebih banyak tentang pekerjaan sebelumnya tentang ini jika saya punya waktu. Jelas banyak pemikiran dan upaya telah dilakukan untuk ini, dan saya tentu tidak ingin memblokir banyak hal. Saya hanya ingin menyampaikan kekhawatiran dan pertanyaan saya ketika mencoba menangani hal ini.

@ Matthias

Jika Lepas pin secara otomatis diturunkan (dengan cara yang sama seperti Sync / Send) maka saya pikir ini seharusnya tidak menjadi masalah.

Saya tidak yakin apakah saya jelas. Untuk memperjelas, sangat aman untuk memindahkan sekitar jenis !Unpin dan dengan demikian sangat aman untuk mem::swap mereka sekitar. Hanya tidak aman untuk memindahkan tipe T: !Unpin setelah disematkan, yaitu di dalam Pin<P<T>> .

Misalnya, dalam kode async / await, Anda dapat memindahkan masa depan yang dikembalikan dari fungsi asinkron sebanyak yang Anda inginkan. Anda hanya berhenti dapat memindahkannya setelah Anda pin_mut! atau memasukkannya ke dalam Pin<Box<..>>> atau yang lainnya.

Saya punya beberapa macam pertanyaan tentang ini:

  1. Mengingat pentingnya Pin<T> untuk async dan untuk generator dan potensi ketidaknyamanan saat berinteraksi dengan bagian lain Rust (misalnya swap & replace ), memiliki verifikasi formal (misalnya oleh @jhjourdan atau @RalfJung) telah dilakukan untuk varian API pinning yang diusulkan di sini?

  2. Apakah API ini memberikan jaminan baru tentang mesin abstrak / semantik operasional Rust? Yaitu, jika kita lupa tentang use case sebagai mekanisme pendukung untuk async & await / generator, dapatkah kita meletakkan ini di dalam peti di ekosistem dan itu hanya akan berfungsi mengingat jaminan saat ini kita memberikan?

  3. Jenis API atau jenis penambahan sistem apa yang menjadi tidak mungkin sebagai akibat dari menstabilkan API penyematan? (pertanyaan ini merupakan perpanjangan dari 2.)

  4. Cara apa yang disediakan API yang akan distabilkan dalam hal mengembangkannya, bahasa yang disediakan tipe &pin T untuk meningkatkan proyeksi lapangan dan semacamnya (yang tampaknya tidak bagus dengan API yang diusulkan).

Saya punya beberapa macam catatan:

  1. Dokumentasi di pustaka standar tampaknya cukup jarang. :(

  2. Saya setuju dengan orang lain bahwa konstruksi pinning cukup melelahkan / kompleks secara mental.

  3. Contoh Unmovable dalam dokumentasi tampaknya terlalu rumit dan melibatkan unsafe ; ini tampaknya kurang optimal. Dengan inisialisasi bertahap seperti yang diuraikan dalam draf RFC dalam bahasa (yaitu, meningkatkan NLL) sebagai gantinya dapat memberi kita:

struct Unmovable<'a> {
    data: String,
    slice: &'a str,
}

let um: Unmovable<'_>;
um.data = "hello".to_string();
um.slice = &um.data; // OK! we borrow self-referentially.

drop(um); // ERROR! `um.slice` is borrowing `um.data` so you cannot move `um`.

// You won't be able to take a &mut reference to `um` so no `swap` problems.

Ini tidak melibatkan nol tidak aman dan cukup mudah bagi pengguna untuk menangani ini.

Selain itu, std API tidak menyediakan cara yang aman untuk menyematkan objek ke tumpukan.
Ini karena tidak ada cara untuk mengimplementasikannya dengan aman menggunakan API fungsi.

Bagaimana dengan API seperti ini?

pub fn using_pin<T, R, F>(value: T, f: F) -> R
where F: for<'a> FnOnce(Pin<&'a mut T>) -> R {
    pin_mut!(value);    // Actual implementation inlines this but the point is this API is safe as long as pin_mut! is safe.
    f(value)
}

Saya belum mengikuti perkembangan API pinning terlalu dekat, jadi ini bisa saja disebutkan atau dijelaskan di tempat lain dan saya tidak dapat menemukannya, mohon maaf jika itu masalahnya:

Tipe Pinned adalah ZST yang tidak mengimplementasikan Unpin ; itu memungkinkan Anda untuk
tekan implementasi otomatis Unpin pada stable, dimana !Unpin impls
belum stabil.

Adakah penjelasan di mana pun tentang mengapa !Unpin impls tidak dapat dibuat stabil?

Ini hanya aman jika Foo (tipe yang mengandung) tidak repr (dikemas),
karena hal ini menyebabkan bidang dipindahkan untuk menyetel kembali.

Apakah dikemas berarti bidang dapat dipindahkan secara dinamis? Itu agak menakutkan. Apakah kami yakin bahwa llvm tidak akan pernah menghasilkan kode untuk memindahkan bidang dalam keadaan lain? Demikian juga, mungkinkah nilai yang disematkan pada tumpukan dapat dipindahkan oleh llvm?

Terlepas dari kehalusannya, ini sepertinya API yang sangat bagus. Kerja bagus!

@Centril Ralf telah menulis tentang di blognya .

API pin tidak melibatkan perubahan bahasa sama sekali, dan sepenuhnya diterapkan di pustaka standar menggunakan fitur bahasa yang sudah ada sebelumnya. Ini tidak berdampak pada Rust bahasa dan tidak menyita fitur bahasa lainnya.

Pin sebenarnya hanyalah implementasi cerdas dari salah satu fitur Rust yang paling berharga dan klasik: kemampuan untuk memperkenalkan invarian ke API dengan menandai bagian dari API unsafe . Pin membungkus penunjuk untuk membuat satu operasi ( DerefMut ) tidak aman, mengharuskan orang yang melakukannya untuk menegakkan invarian tertentu (bahwa mereka tidak keluar dari referensi), dan mengizinkan kode lain untuk berasumsi bahwa ini tidak akan pernah terjadi. Contoh serupa, jauh lebih tua dari trik yang sama ini adalah String , yang membuatnya tidak aman untuk meletakkan byte non-UTF8 ke dalam string, memungkinkan kode lain untuk mengasumsikan bahwa semua data dalam String adalah UTF8.

Apakah ada penjelasan di mana pun tentang mengapa! Unpin impls tidak dapat dibuat stabil?

Implikasi negatif saat ini tidak stabil, sama sekali tidak terkait dengan API ini.

Implikasi negatif saat ini tidak stabil.

🤦‍♂️ Itu masuk akal, seharusnya sudah memikirkannya sedikit lebih lama. Terima kasih.

@alexcrichton Itulah beberapa analisis hebat dari API ini, kita harus mencoba untuk mempertahankannya di tempat yang lebih baik daripada beberapa komentar yang akan hilang!

Beberapa komentar:

as_mut : Pertanyaan: bagaimana dengan impl DerefMut yang "jahat"? Ini adalah cara yang aman
untuk memanggil DerefMut yang disediakan pengguna yang mengelompokkan & mut P :: Target secara asli,
mungkin mengizinkannya untuk memodifikasinya juga. Bagaimana ini aman?

Pada dasarnya, ketika Anda memanggil new_unchecked , Anda membuat janji tentang implementasi Deref dan DerefMut untuk tipe ini.

set : Pin yang Diberikan

(dan fakta bahwa kita tidak tahu apa-apa
Lepas pin), bukankah ini harus menjamin bahwa P :: Target tidak pernah bergerak? Jika kita bisa
menginisialisasi ulang dengan P :: Target lain, bukankah seharusnya ini tidak aman?
Atau apakah ini terkait dengan destruktor dan semua itu?

Ini menjatuhkan konten lama dari penunjuk, dan menempatkan konten baru di sana. "Pinned" bukan berarti "tidak pernah jatuh", itu artinya "tidak pernah dipindahkan sampai dijatuhkan". Jadi Menjatuhkan atau menimpanya sambil memanggil drop tidak masalah. Memanggil drop sangat penting, itulah jaminan penurunan yang saya sebutkan di atas.

Di mana Anda melihat sesuatu bergerak di sini?

map_unchecked : Pertanyaan :: apa contoh penghitungnya di sini? Jika ini aman, apa contoh yang menunjukkan pelanggaran jaminan Pin?

Contoh akan dimulai dengan Pin<&&T> dan menggunakan metode ini untuk mendapatkan Pin<&T> . Memasang pin tidak "menyebar melalui" referensi.

get_ref : Satu "mungkin gotcha" di sini adalah mutabilitas interior, bagaimana jika T ada
RefCell?

Memang, ini gotcha, tapi seperti yang Anda amati bukan masalah kesehatan. Apa yang tidak masuk akal adalah memiliki metode yang berubah dari Pin<RefCell<T>> menjadi Pin<&[mut] T> . Pada dasarnya, yang terjadi adalah RefCell tidak menyebarkan pin, kita dapat impl<T> Unpin for RefCell<T> .

apakah telah dilakukan verifikasi formal (misalnya oleh @jhjourdan atau @RalfJung) untuk varian API pinning yang diusulkan di sini?

Tidak, bukan dari pihak kami. Posting blog yang saya sebutkan di atas berisi beberapa pemikiran tentang bagaimana saya akan mulai memformalkan ini, tetapi kami belum benar-benar melakukannya dan melakukannya. Jika Anda memberi saya mesin waktu atau mahasiswa PhD yang tertarik, kami akan melakukannya. ;)

jika kita lupa tentang use case sebagai mekanisme pendukung untuk async & await / generator, dapatkah kita meletakkan ini di dalam peti di ekosistem dan itu hanya akan berfungsi mengingat jaminan saat ini yang kita berikan?

Itu niatnya.

Jenis API atau jenis penambahan sistem apa yang menjadi tidak mungkin sebagai akibat dari menstabilkan API penyematan? (pertanyaan ini merupakan perpanjangan dari 2.)

Uh, saya tidak tahu bagaimana menjawab pertanyaan itu dengan percaya diri. Ruang penambahan yang mungkin terlalu besar dan juga dimensi yang terlalu tinggi sehingga saya berani membuat pernyataan universal apa pun tentangnya.

Jalan apa yang disediakan API yang akan distabilkan dalam hal mengembangkannya bahasa yang disediakan & jenis pin T untuk meningkatkan proyeksi lapangan dan semacamnya (yang tampaknya tidak bagus dengan API yang diusulkan).

Saya tidak yakin lagi tentang &pin T , ini tidak cocok dengan generik baru Pin<T> . Dalam hal menangani proyeksi, kita memerlukan beberapa peretasan untuk mengatakan " Unpin dan Drop belum diterapkan untuk jenis ini", lalu kita dapat melakukannya dengan aman dengan makro. Untuk ergonomi tambahan, kami mungkin menginginkan kapabilitas "proyeksi lapangan" generik dalam bahasa tersebut, yang juga mencakup mulai dari &Cell<(A, B)> hingga &Cell<A> .

Apakah ada penjelasan di mana pun tentang mengapa! Unpin impls tidak dapat dibuat stabil?

Implikasi negatif AFAIK memiliki beberapa batasan lama, dan jika Anda menambahkan batasan umum padanya, implik tersebut seringkali tidak berfungsi seperti yang Anda kira. (Batas umum terkadang diabaikan begitu saja, atau lebih.)

Mungkin Chalk memperbaiki semua ini, mungkin hanya sebagian, tapi bagaimanapun kita mungkin tidak ingin memblokir ini di Chalk.

Apakah dikemas berarti bidang dapat dipindahkan secara dinamis? Itu agak menakutkan.

Ini adalah satu-satunya cara yang tepat untuk memanggil drop pada bidang yang dikemas, mengingat bahwa drop mengharapkan referensi yang selaras.

Apakah kami yakin bahwa llvm tidak akan pernah menghasilkan kode untuk memindahkan bidang dalam keadaan lain? Demikian juga, mungkinkah nilai yang disematkan pada tumpukan dapat dipindahkan oleh llvm?

LLVM menyalin byte di sekitar seharusnya tidak menjadi masalah, karena tidak dapat mengubah perilaku program. Ini tentang konsep tingkat yang lebih tinggi tentang "memindahkan" data, dengan cara yang dapat diamati di Rust (misalnya karena petunjuk ke data tidak lagi mengarah ke sana). LLVM tidak bisa hanya memindahkan data ke tempat lain yang mungkin kita punya petunjuk. Demikian pula, LLVM tidak bisa begitu saja memindahkan nilai pada tumpukan yang alamatnya diambil.

Ok terima kasih @RalfJung , masuk akal! Beberapa pertanyaan lanjutan ...

Ketika Anda mengatakan "tidak pernah pindah sampai dijatuhkan", ini berarti bahwa Drop dapat dipanggil di mana &mut self telah pindah dari alamat Pin<&mut Self> ? Destruktor tidak bisa mengandalkan petunjuk interior yang akurat, bukan?

Kekhawatiran saya ketika melihat set adalah bagaimana kepanikan akan ditangani, tetapi saya pikir ini bukan masalah setelah menggali lebih dalam codegen.

Ketika Anda mengatakan "tidak pernah pindah sampai dijatuhkan", ini berarti bahwa Drop dapat dipanggil di mana &mut self telah pindah dari alamat Pin<&mut Self> ? Destruktor tidak bisa mengandalkan petunjuk interior yang akurat, bukan?

@alexcrichton pemahaman saya adalah itu berarti tidak pernah pindah sampai setelah Drop::drop kembali. Jika tidak, beberapa kasus penggunaan (koleksi yang mengganggu dan setidaknya buffer DMA yang dialokasikan tumpukan) menjadi tidak mungkin.

Destructors dapat mengandalkan sesuatu yang tidak pernah dipindahkan jika mereka dapat membuktikannya sebelumnya dengan Pin . Misalnya jika mesin negara hanya bisa memasuki keadaan melalui API yang mengharuskannya untuk disematkan, destruktor dapat berasumsi bahwa itu disematkan sebelum dijatuhkan jika dalam keadaan itu.

Kode tidak dapat berasumsi bahwa destruktor nonlokal tidak memindahkan anggota, tetapi jelas Anda dapat berasumsi bahwa destruktor Anda sendiri tidak memindahkan barang karena Andalah yang menulisnya.

Ketika Anda mengatakan "tidak pernah pindah sampai dijatuhkan", ini berarti Jatuhkan dapat dipanggil di mana & mut self telah pindah dari alamat Pin <& mut Self>? Destruktor tidak bisa mengandalkan petunjuk interior yang akurat, bukan?

Maksud saya, data tidak akan pernah berpindah (dalam arti tidak akan pergi ke tempat lain, termasuk tidak dialokasikan) sampai drop dipanggil. Dan ya, drop dapat diandalkan untuk menjalankan lokasi yang disematkan, meskipun tipenya tidak dapat mengungkapkannya. drop harus mengambil Pin<&mut self> (untuk semua jenis), tapi sayangnya, sudah terlambat untuk itu.

Setelah drop dipanggil, datanya hanyalah byte yang tidak berarti, Anda dapat melakukan apa saja dengannya: Taruh barang baru di sana, hapus alokasi, apa pun.

Hal ini memungkinkan, misalnya, daftar tertaut yang mengganggu di mana destruktor suatu elemen membatalkan pendaftarannya dengan menyesuaikan penunjuk yang bersebelahan. Kami tahu memori tidak akan hilang tanpa pemanggilan destruktor itu. (Elemen masih bisa bocor , dan kemudian akan tetap berada di daftar tertaut selamanya. Tapi dalam kasus itu akan tetap menjadi memori yang valid sehingga tidak ada masalah keamanan.)

Saya telah membaca semua yang dapat saya temukan tentang Pin , Unpin , dan diskusi yang mengarah ke semuanya, dan sementara saya _think_ sekarang saya mengerti apa yang sedang terjadi, ada juga banyak tentang kehalusan tentang arti dari berbagai jenis, serta kontrak yang harus diikuti oleh pelaksana dan pengguna. Sayangnya, saya melihat diskusi yang relatif sedikit tentang hal itu di dokumen untuk std::pin atau pada Pin dan Unpin secara khusus. Secara khusus, saya ingin melihat beberapa konten dari komentar ini:

dimasukkan ke dalam dokumen. Secara khusus:

  • Pin hanya melindungi "satu tingkat dalam".
  • Pin::new_unchecked membatasi implikasi untuk Deref dan DerefMut .
  • Interaksi antara Pin dan Drop .
  • Bagaimana !Unpin hanya tidak diperbolehkan untuk dipindahkan setelah ditempatkan di Pin .
  • Alasan mengapa Pin<Box<T>>: Unpin where T: !Unpin . Ini terkait kembali dengan batasan "satu tingkat dalam" di atas, tetapi menurut saya contoh konkret dengan penjelasan yang tepat ini akan membantu pembaca.

Saya menemukan contoh balasan @alexcrichton juga cukup membantu. Memberi pembaca gambaran tentang apa yang bisa salah untuk metode unsafe yang berbeda di luar prosa saya pikir akan banyak membantu (setidaknya itu pasti berhasil untuk saya). Secara umum, karena kehalusan API ini, saya ingin melihat bagian Keamanan dari berbagai metode tidak aman diperluas, dan mungkin juga dirujuk dari dokumen level modul std::pin .

Saya sendiri belum banyak menggunakan API ini, jadi saya akan mempercayai penilaian teknis bahwa ini dalam keadaan baik sekarang. Namun, menurut saya nama Pin , Pinned dan Unpin terlalu mirip dan tidak ekspresif untuk jenis / sifat yang sangat berbeda dan API yang relatif kompleks, yang membuat lebih sulit untuk memahaminya (dibuktikan dengan beberapa komentar di utas ini).

Mereka tampaknya mengikuti konvensi penamaan untuk ciri-ciri penanda, jadi saya tidak bisa mengeluh, tapi saya bertanya-tanya apakah kita bisa membuat tradeoff antara verbositas dan nama yang menjelaskan sendiri:

  • Pinned - agak membingungkan karena katanya sama dengan Pin . Mengingat bahwa itu digunakan seperti PhantomData untuk menambah struct dengan informasi meta yang akan hilang jika tidak, bagaimana dengan PinnedData , PhantomPinned , PhantomSelfRef atau bahkan DisableUnpin ? Sesuatu yang menunjukkan pola penggunaan dan / atau efek yang akan dimilikinya.
  • Unpin - Seperti di https://github.com/rust-lang/rust/issues/55766#issuecomment -437266922, saya bingung dengan nama Unpin , karena "lepas pin "dapat dipahami dengan berbagai cara yang ambigu. Sesuatu seperti IgnorePin , PinNeutral mungkin?

Secara umum saya gagal dan menemukan nama alternatif yang bagus sendiri ...

PhantomPin dan PinNeutral menurut saya adalah nama yang sangat bagus.

Hanya untuk memberikan tandingan, saya telah menemukan Unpin intuitif (setelah saya memahaminya). Pinned lebih sulit untuk dipertahankan, karena saya belum pernah menggunakannya dalam kode saya sendiri. Bagaimana dengan mengubah Pinned menjadi NotUnpin ?

Saya setuju bahwa menemukan nama yang lebih baik mungkin merupakan latihan bikeshedding yang bermanfaat untuk memudahkan pembicaraan tentang pemasangan pin. Saya melamar:

  • Pin -> Pinned : Ketika Anda diberi Pin , itu benar-benar janji bahwa apa yang Anda berikan _telah disematkan_, dan _ tetap_ disematkan selamanya. Saya tidak merasa terlalu kuat tentang hal ini, karena Anda _bisa_ juga berbicara tentang diberi "pin nilai". Pinned<Box<T>> lebih baik bagi saya, terutama karena hanya Box yang disematkan, bukan isinya.
  • Unpin -> Repin : untuk ciri-ciri penanda lainnya, kita biasanya membicarakan tentang apa yang dapat Anda lakukan dengan sesuatu yang memiliki ciri penanda itu. Yang mungkin mengapa Unpin dipilih di tempat pertama. Namun, saya pikir apa yang benar-benar kami ingin pembaca ambil di sini adalah sesuatu yang Unpin dapat disematkan, dan kemudian disematkan kembali di tempat lain, tanpa konsekuensi atau pertimbangan. Saya juga menyukai saran @ mark-im tentang PinNeutral , meskipun agak lebih bertele-tele.
  • Pinned -> PermanentPin : Menurut saya Pinned bukan nama yang bagus, karena sesuatu yang mengandung Pinned tidak benar-benar disematkan .. Itu bukan hanya Unpin . PhantomPin memiliki masalah serupa karena mengacu pada Pin , ketika Pin bukanlah hal yang ingin Anda capai. NotUnpin memiliki double negative, yang membuatnya sulit untuk dipikirkan. Sugesti @Kimundi sebesar PhantomSelfRef cukup mendekati, meskipun menurut saya ini sedikit "rumit", dan ini mengikat properti "tidak dapat dipindahkan setelah disematkan" dengan satu contoh di mana itu terjadi (ketika Anda memiliki referensi sendiri). Saran saya juga bisa diutarakan sebagai PermanentlyPinned ; Saya tidak tahu bentuk mana yang kurang buruk.

Saya pikir Pinned seharusnya menjadi NotX dimana X adalah apapun yang akhirnya dinamai Unpin . Pekerjaan satu-satunya dari Pinned adalah membuatnya sehingga tipe penutup tidak mengimplementasikan Unpin . (Edit: dan jika kita mengubah Unpin ke sesuatu yang lain, mungkin double negative tidak menjadi masalah)

Repin tidak masuk akal bagi saya, karena "Jenis ini dapat disematkan di tempat lain" hanyalah efek samping dari "Jenis ini dapat dipindahkan dari pin".

@tikue Dalam beberapa hal saya merasakan hal yang sama, tetapi sebaliknya. Saya pikir Unpin harus diutarakan dalam negatif "ini _not_ dibatasi oleh Pin ", sedangkan Pinned harus diutarakan dalam positif "ini _is_ dibatasi oleh Pin ". Sebagian besar hanya untuk menghindari negatif ganda. Tapi itu detailnya; Saya suka gagasan tentang adanya dualitas. Mungkin: s/Unpin/TemporaryPin , s/Pinned/PermanentPin ?

EDIT: Ya, saya melihat maksud Anda tentang Repin menjadi efek samping dari Unpin . Saya ingin mengkomunikasikan fakta bahwa Pin "tidak penting" untuk jenis yang Unpin , yang menurut saya Unpin tidak bekerja dengan sangat baik. Oleh karena itu saran di atas TemporaryPin .

@jonhoo Saya pikir alasan utama saya lebih suka yang sebaliknya adalah karena Pinned mencegah suatu sifat diterapkan, jadi itu, dalam arti yang paling jelas bagi saya, negatif sebenarnya.

Sunting: bagaimana dengan:

Unpin -> Escape
Pinned -> NoEscape

Menarik .. Saya mencoba untuk melihat bagaimana itu cocok dengan dokumentasi. Sesuatu seperti:

Secara umum, ketika Anda diberi Pin<P> , itu disertai dengan jaminan bahwa target P tidak akan bergerak sampai target itu dijatuhkan. Pengecualian untuk ini adalah jika target P adalah Escape . Jenis yang ditandai sebagai Escape janji bahwa mereka tetap valid meskipun dipindahkan (misalnya, tidak berisi referensi sendiri internal), dan karena itu diizinkan untuk "keluar" dari Pin . Escape adalah sifat otomatis, jadi semua jenis yang seluruhnya terdiri dari jenis yang Escape itu sendiri juga Escape . Pelaksana dapat memilih keluar dari ini pada malam hari menggunakan impl !Escape for T {} , atau dengan memasukkan penanda NoEscape dari std::phantom .

Tampaknya cukup baik, meskipun kaitannya dengan kata "melarikan diri" tampaknya agak renggang. Secara terpisah, tulisan di atas juga membuat saya menyadari bahwa Pin<P> tidak _really_ menjamin bahwa target P tidak akan dipindahkan (justru karena Unpin ). Alih-alih, ini menjamin bahwa _either_ tidak masalah jika target P bergerak _atau_ P target tidak akan dipindahkan. Tidak tahu bagaimana menggunakannya untuk menginformasikan pilihan nama yang lebih baik ... Tapi itu mungkin sesuatu yang harus dimasukkan ke dalam dokumen dengan satu atau lain cara.

Secara pribadi, saya juga sangat tidak menyukai Unpin sebagai nama, mungkin karena paling sering dilihat sebagai impl !Unpin yang berbunyi "not-un-pin" dan memerlukan beberapa siklus otak (saya Saya adalah model lama) untuk menyimpulkan bahwa itu berarti "oke, ini akan disematkan selamanya setelah disematkan pertama kali", jadi saya bahkan tidak dapat mengoptimalkan negatif ganda.
Secara umum, manusia cenderung lebih sulit berpikir negatif daripada positif (tanpa sumber langsung, tapi lihat karya Richard Hudson jika ragu).
Btw Repin kedengarannya sangat menyenangkan bagiku.

Pin sulit dijelaskan karena tidak selalu membuat nilai yang disematkan tidak dapat dipindahkan. Pinned membingungkan karena sebenarnya tidak menyematkan apa pun. Ini hanya mencegah keluarnya Pin .

Pin<P<T>> dapat dijelaskan sebagai nilai yang disematkan: nilai yang disematkan tidak dapat bergerak kecuali nilainya adalah tipe yang dapat lolos dari pin.

Beberapa googling cepat tampaknya menunjukkan bahwa dalam gulat, ketika seseorang disematkan, melanggar pin disebut melarikan diri .

Saya juga menyukai istilah escape daripada Unpin tapi saya akan memilih EscapePin .

Banyak pemikiran bagus di sini!

Satu hal umum: Bagi saya sebagai non-native speaker Pin dan Unpin kebanyakan adalah kata kerja / tindakan. Meskipun Pin masuk akal, karena objek disematkan ke satu lokasi memori pada satu waktu, saya tidak dapat melihat hal yang sama untuk Unpin . Setelah saya menerima referensi Pin<&mut T> , T akan selalu disematkan dalam arti lokasi memorinya stabil, entah itu Unpin atau tidak. Tidak mungkin benar-benar melepas pin objek sebagai tindakan. Perbedaannya adalah bahwa jenis Unpin tidak memerlukan jaminan penyematan untuk ditegakkan dalam interaksi lebih lanjut. Mereka tidak mengacu pada dirinya sendiri, dan alamat memorinya, misalnya, tidak dikirim ke objek lain dan disimpan di sana.

Saya setuju dengan @tikue bahwa alangkah baiknya memiliki karya yang mencolok untuk apa sebenarnya arti Unpin , tetapi sulit untuk diukur. Bukankah hanya tipe-tipe itu yang bisa dipindah-pindah, dan itu juga bukan murni kurangnya referensi diri mereka? Mungkin itu adalah sesuatu tentang "tidak ada petunjuk di seluruh ruang memori yang tidak valid saat objek dipindahkan". Kemudian sesuatu seperti StableOnMoveAfterPin , atau hanya StableMove mungkin bisa menjadi pilihan, tapi itu juga terdengar tidak terlalu bagus.

Repin bagi saya memiliki komplikasi yang sama seperti Unpin , yang berarti bahwa satu hal pertama kali dilepas - yang menurut pemahaman saya tidak terjadi.

Karena sifat tersebut sebagian besar mendefinisikan apa yang terjadi setelah seseorang melihat Pin dari jenis tersebut, saya menemukan hal-hal seperti PinNeutral , atau PinInvariant tidak terlalu buruk.

Mengenai Pin vs Pinned , saya pikir saya lebih suka Pinned , karena itulah status penunjuk pada titik waktu ketika seseorang melihatnya.

@ Matthias247 Saya tidak berpikir bahwa Anda dijamin bahwa P::Target alamat stabil jika P: Unpin ? Saya bisa saja salah tentang ini?

@Mutiarasni

Setelah saya menerima referensi Pin <& mut T>, T akan selalu disematkan dalam arti lokasi memorinya stabil, terlepas dari Lepas pin atau tidak.

Bisakah Anda menjelaskan apa yang Anda maksud dengan ini? Diberikan T: Unpin Anda dapat menulis sebagai berikut:

let pin_t: Pin<&mut T> = ...
let mut other_t: T = ...
mem::replace(Pin::get_mut(pin_t), &mut other_t);
// Now the value originally behind pin_t is in other_t

@jonhoo Sebenarnya pertanyaan yang bagus. Alasan saya adalah bahwa masa depan dikotak, dan kemudian metode poll() akan dipanggil pada alamat memori yang sama. Tapi itu jelas hanya berlaku untuk tugas tingkat atas / masa depan, dan lapisan perantara mungkin bergerak di masa depan ketika mereka Unpin . Jadi sepertinya Anda benar.

Wrt bikeshedding terbaru:

  • Unpin : bagaimana dengan MoveFromPin ? Jika saya masih tidak melewatkan beberapa kehalusan, saya pikir ini secara langsung menyatakan kemampuan apa yang sebenarnya diaktifkan oleh sifat tersebut: jika jenisnya berada dalam Pin , Anda masih dapat memindahkannya.

    Yang terpenting, ini semacam mengatakan hal yang sama seperti Unpin , tetapi dibingkai sebagai pernyataan positif, jadi alih-alih negatif ganda !Unpin kita sekarang memiliki !MoveFromPin . Saya pikir saya menemukan itu lebih mudah untuk ditafsirkan, setidaknya ... itu eh, jenis yang tidak bisa Anda pindahkan dari pin.

    (Ada beberapa ruang untuk variasi pada ide dasar: MoveOutOfPin , MoveFromPinned , MoveWhenPinned , dan seterusnya.)

  • Pinned : ini kemudian bisa menjadi NoMoveFromPin , dan efeknya adalah membuat tipe !MoveFromPin . Saya pikir itu tampaknya cukup mudah.

  • Pin itu sendiri: yang satu ini tidak terhubung dengan dua lainnya dan juga tidak terlalu signifikan, tapi saya pikir mungkin ada ruang untuk sedikit perbaikan di sini juga.

    Masalahnya adalah bahwa Pin<&mut T> (misalnya) tidak berarti bahwa &mut disematkan, itu berarti T adalah (kebingungan yang menurut saya pernah saya lihat di setidaknya satu bukti komentar terbaru). Karena bagian Pin bertindak sebagai semacam pengubah pada &mut , saya pikir ada kasus bahwa akan lebih baik menyebutnya Pinning .

    Ada beberapa preseden tidak langsung untuk ini: jika kita ingin memodifikasi semantik overflow dari tipe integer untuk membungkus alih-alih panik, kita katakan Wrapping<i32> daripada Wrap<i32> .

Semua ini lebih panjang dari aslinya, tetapi mengingat betapa rumitnya beberapa alasan di sekitarnya, ini mungkin investasi yang berharga untuk kejelasan yang lebih besar.

Re: Repin , Saya berharap ini menjadi sesuatu seperti

unsafe trait Repin {
    unsafe fn repin(from: *mut Self, to: *mut Self);
}

yang dapat digunakan untuk mendukung !Unpin jenis di dalam Vec -seperti koleksi yang kadang-kadang bergerak isinya (ini bukan usulan untuk menambahkan sifat seperti sekarang atau pernah, hanya kesan pertama saya dari nama sifat).

Juga bikshedding nama:

  • Pin<P> -> Pinned<P> : nilai pointer P poin akan disematkan di memori selama masa pakainya (sampai dijatuhkan).
  • Unpin -> Moveable : nilai tidak perlu disematkan dan dapat dengan bebas dipindahkan.
  • Pinned (struct) -> Unmoveable : harus Pinned dan tidak dapat dipindahkan.

Saya tidak berpikir Pin atau Unpin harus berubah, semua alternatif menambah verbositas tanpa kejelasan menurut saya, atau bahkan cukup menyesatkan. Kami juga sudah melakukan percakapan ini, memutuskan untuk menggunakan Pin dan Unpin , dan tidak ada argumen yang muncul di utas ini yang baru.

Namun, Pinned telah ditambahkan sejak diskusi sebelumnya, dan menurut saya masuk akal untuk membuatnya menjadi PhantomPinned untuk memperjelas jenis penanda hantu seperti PhantomData .

Secara pribadi, saya juga sangat tidak menyukai Lepas Pin sebagai nama, mungkin karena ini paling sering dilihat sebagai impl! Lepas pin yang bertuliskan "not-un-pin" dan memerlukan beberapa siklus otak (saya model yang lebih tua) untuk menyimpulkan yang artinya "oke, ini akan disematkan selamanya setelah disematkan pertama kali", jadi saya bahkan tidak bisa mengoptimalkan negatif ganda.

Ini benar-benar kebalikan dari pengalaman saya, menerapkan secara manual !Unpin berarti Anda menerapkan struktur referensi sendiri dengan tangan menggunakan kode yang tidak aman, kasus penggunaan yang sangat khusus. Sebaliknya, apa pun yang menyimpan struct yang berpotensi melepas pin di belakang pointer memiliki implikasi positif Unpin . Semua implik dari Unpin di std adalah polaritas positif, misalnya.

@withoutboats dapatkah Anda memberikan tautan ke diskusi sebelumnya seputar nama-nama ini di mana argumen yang dikemukakan di sini telah diperdebatkan?

Ini satu utas, meskipun jelas juga dibahas di utas RFC dan masalah pelacakan https://internals.rust-lang.org/t/naming-pin-anchor-move/6864

(jenis di utas ini disebut jangkar dan pin sekarang disebut Pin<Box<T>> dan Pin<&'a mut T> )

Apakah Lepas pin seharusnya dibaca sebagai singkatan dari Unpinnable? Unpinnable karena Anda tidak dapat benar-benar menyimpan nilai yang disematkan, meskipun itu di dalam Pin. (Apakah itu pemahaman yang benar di pihak saya?)

Saya telah melihat-lihat beberapa dokumen dan utas komentar dan tidak melihat referensi apa pun ke Unpinnable secara khusus.

Lepas pin seharusnya tidak berarti apa pun. Satu hal yang menurut saya tidak jelas bagi banyak pengguna, tetapi benar, adalah bahwa panduan gaya pustaka standar lebih memilih kata kerja sebagai nama sifat, bukan kata sifat - karenanya Send , bukan Sendable . Ini belum diterapkan dengan konsistensi yang sempurna, tetapi ini adalah norma. Unpin adalah seperti dalam "melepas pin", karena jenis ini dapat dilepas dari Pin yang telah Anda sematkan.

Nama seperti Move (bukan "dapat dipindahkan", ingat) kurang jelas daripada Unpin karena menyiratkan bahwa ini berkaitan dengan kemampuan untuk memindahkannya sama sekali, daripada menghubungkan perilaku ke jenis pin. Anda dapat memindahkan jenis !Unpin , karena Anda dapat memindahkan nilai Sized di Rust.

Nama yang keseluruhan frase seperti yang saya lihat disarankan akan sangat tidak otomatis untuk std.

Ini mungkin tidak singkat, tapi itulah cara saya membacanya. Karena sifat adalah kata kerja, Anda harus mengubahnya secara manual menjadi kata sifat jika Anda ingin menggunakannya untuk mendeskripsikan sebuah tipe daripada operasi pada sebuah tipe; std::iter::Iterator diimplementasikan oleh sesuatu yang bisa diulang, std::io::Seek diimplementasikan oleh sesuatu yang bisa dicari, std::pin::Unpin diimplementasikan oleh sesuatu yang tidak bisa diubah.

@withoutboats ada masalah khusus dengan beberapa nama lain yang tidak memiliki masalah kata kerja, misalnya Escape atau EscapePin ? Memahami bahwa diskusi ini telah terjadi sebelumnya, tetapi mungkin lebih banyak perhatian tertuju pada ini sekarang, jadi saya tidak yakin ini adalah pengulangan yang sepenuhnya berlebihan ...

Satu hal yang menurut saya benar adalah sangat disayangkan bahwa Pin dan Unpin dapat dibaca sebagai pasangan (beberapa tipe adalah "pin" dan beberapa "lepas pin"), ketika Pin seharusnya menjadi kata benda , bukan kata kerja . Fakta bahwa Pin bukanlah sifat mudah-mudahan dapat menjelaskan banyak hal. Argumen yang mendukung Pinning masuk akal, tetapi di sini kita menghadapi masalah panjang nama. Terutama karena penerima metode harus mengulang self dua kali, kita akan mendapatkan banyak karakter: self: Pinning<&mut Self> . Tidak yakin bahwa Pinning<P> adalah keseluruhan empat karakter yang bernilai lebih dari Pin<P> .

@tikue , terminologi "melarikan diri" jauh lebih kelebihan beban daripada menjepit, menurut saya, bertentangan dengan konsep seperti analisis melarikan diri.

Kami juga sudah melakukan percakapan ini, mengambil keputusan untuk menggunakan Pin dan Lepas Pin, dan tidak ada argumen yang muncul di utas ini yang baru.

Ini membuat saya salah paham - apakah laporan pengalaman komunitas tidak diinginkan? Saya pribadi tidak melihat masalah yang jelas dengan Unpin hingga beberapa komentar lain di utas ini, serta penjajaran dengan negatif ganda Pinned .

Rust tidak melakukan analisis melarikan diri, jadi saya tidak yakin saya melihatnya sebagai masalah nyata.

: bell: Ini sekarang memasuki periode komentar terakhirnya , sesuai ulasan di atas . :lonceng:

Saya masih ingin melihat peningkatan dokumentasi seperti yang diuraikan di https://github.com/rust-lang/rust/issues/55766#issuecomment-438316891 sebelum ini hadir :)

Saya telah membuka https://github.com/rust-lang/rust/pull/55992 untuk menambahkan dokumentasi yang disarankan di atas dan mengganti nama Pinned menjadi PhantomPinned .

Saya pikir Pinned (dan PhantomPinned ) mendorong konsep nilai "yang disematkan" sebagai nilai yang tidak dapat keluar dari Pin , yang berarti banyak nilai dalam Pin (yang tipenya impl Unpin ) tidak "disematkan"!

Sepertinya membingungkan. Saya merasa lebih mudah untuk mengkonseptualisasikan semua nilai dalam Pin seperti yang disematkan saat berada di Pin , dan apakah disematkan permanen atau tidak adalah apa yang sebelumnya dinamai Pinned kontrol. Nama yang terpisah dari Pin* akan mencegah penggabungan dua konsep yang berbeda.

PhantomNotUnpin : P

Secara pribadi, saya juga sangat tidak menyukai Lepas Pin sebagai nama, mungkin karena ini paling sering dilihat sebagai impl! Lepas pin yang bertuliskan "not-un-pin" dan memerlukan beberapa siklus otak

Terima kasih! Saya juga pernah terganggu oleh Unpin selama beberapa waktu bot tidak bisa pin-point (heh) kenapa. Sekarang saya pikir saya mengerti: Ini adalah negasi ganda.

Ini benar-benar kebalikan dari pengalaman saya, menerapkan secara manual! Lepas pin berarti Anda menerapkan struktur referensi mandiri dengan tangan menggunakan kode yang tidak aman, kasus penggunaan yang sangat khusus. Sebaliknya, apa pun yang menyimpan struct yang berpotensi melepas pin di belakang penunjuk memiliki implikasi positif dari Lepas Pin. Semua implik dari Unpin di std adalah polaritas positif, misalnya.

Ini bukan hanya tentang implementasi, juga tentang diskusi. impl !Sync cukup langka (tidak sendirian karena tidak stabil), tetapi membicarakan tentang jenis Sync dan !Sync cukup umum. Demikian pula, !Unpin muncul cukup banyak dalam diskusi tentang fitur ini, setidaknya yang saya miliki.

Saya, juga, lebih suka sesuatu yang secara positif mengungkapkan properti ( MoveFromPin atau lebih). Saya tidak sepenuhnya yakin dengan ergonomi, karena tidak seperti Pin seseorang seharusnya tidak perlu terlalu sering menulis sifat ini terikat.

Rust tidak melakukan analisis melarikan diri, jadi saya tidak yakin saya melihatnya sebagai masalah nyata.

LLVM melakukannya, jadi analisis pelarian masih cukup relevan dengan Rust.

Cara mengatasinya adalah dengan memilih kata-kata yang membalikkan arti dari Pin / Unpin . Misalnya, ganti nama Unpin menjadi Relocate . Kemudian !Unpin menjadi !Relocate . Itu jauh lebih masuk akal bagi saya - saya membacanya sebagai "Oh, objek jenis ini tidak dapat dipindahkan". Pesaing lainnya adalah Movable .

Saya tidak yakin apa kata kebalikannya yang bisa menggantikan Pin , atau bahkan jika kita perlu. Tapi saya pasti bisa membayangkan dokumen mengatakan sesuatu seperti ini:

Objek yang disematkan dapat dimodifikasi secara langsung melalui DerefMut jika dan hanya jika objek tersebut dapat dipindahkan ke memori. Relocate adalah sifat otomatis - ini ditambahkan secara default. Tetapi jika akan ada petunjuk langsung ke memori yang menyimpan nilai Anda, pilih keluar dari Relocate dengan menambahkan impl !Relocate pada tipe Anda.

impl<T: Relocate> DerefMut for Pin<T> { ... }

Bagi saya ini jauh lebih masuk akal daripada Unpin .

Saya telah membuka # 55992 untuk menambahkan dokumentasi yang disarankan di atas

Ini hanya menambahkan sebagian dari apa yang disarankan di https://github.com/rust-lang/rust/issues/55766#issuecomment -438316891.

Saya suka saran MoveFromPin . Relocate juga bagus, tapi mungkin tidak terkait dengan Pin cukup. Seseorang dapat lagi memahaminya sebagai tipe yang tidak dapat dipindahkan (yang sebenarnya bukan). RelocateFromPin lagi-lagi akan bagus.

Escape ing adalah hal yang juga diasosiasikan di Swift dengan closure, dan apakah mereka dipanggil di dalam atau di luar rantai panggilan saat ini. Kedengarannya menyesatkan.

Saya tidak melihat ada masalah dengan nama yang lebih panjang selama itu membantu kejelasan.

FWIW Saya ingin memberikan suara juga untuk mengganti nama Unpin menjadi sesuatu yang "positif" seperti Relocate atau MoveFromPin (atau bahkan lebih panjang lebar tetapi mungkin sedikit lebih akurat MayMoveFromPin ).

Saya setuju bahwa negatif ganda !Unpin atau hanya Unpin telah membingungkan saya secara historis, dan sesuatu yang dibingkai dalam positif "ini dapat bergerak meskipun berada di dalam Pin " Saya pikir akan membantu mengurangi kebingungan!

FWIW Saya awalnya memikirkan hal yang sama tentang Unpin , tetapi ketika saya benar-benar menggunakannya IMO itu masuk akal - itu sebenarnya bukan negasi ganda, karena operasi yang Anda cari adalah kemampuan untuk Unpin (mengambil sesuatu yang masuk dan keluar Pin bebas) bukan kemampuan untuk menyimpan sesuatu di dalam pin. Ini sama dengan MoveFromPin , hanya kata-katanya berbeda. Saya lebih suka nama yang tidak membuat orang berpikir itu "bukan Pin " atau semacamnya, tapi IMO MoveFromPin dan lainnya terlalu bertele-tele. UndoPin ? ( FreePin untuk kerumunan haskell?)

Saya masih berpikir !Unpin terbaca aneh - Saya telah melatih suara hati saya untuk memperlakukannya lebih seperti "Jangan lepas pin ini!" daripada yang biasa "Tidak mengimplementasikan Unpin ", tetapi ini membutuhkan usaha.

Bagaimana dengan !Pluck ?

@bayu_joo

bukannya "Tidak menerapkan Lepas pin" yang biasa

Saya menyebutkan ini dalam komentar saya sebelumnya, tetapi saya pikir ini sebenarnya cara yang bagus untuk mengatakannya: Unpin adalah operasi mengambil masuk dan keluar dari Pin<C<_>> . Hal-hal yang tidak menerapkan Unpin tidak menyediakan kemampuan itu.

@cramertj Saya cukup suka UndoPin

@cramertj Saya setuju bahwa saya bukan penggemar berat alternatif yang diusulkan sejauh ini, tetapi saya pribadi akan menyukai kata-kata MoveFromPin lebih dari Unpin . Ini adalah poin yang bagus bahwa ini bukan double-negative, tapi saat membacanya (sebagai seseorang yang belum bekerja sama sekali) itu membuat saya tersandung bahwa itu adalah double negative. Saya terus mencoba membaca awalan "Un" sebagai negatif ...

Saya ingin tahu, tetapi @cramertj atau yang lain apakah Anda merasa ada pegangan yang baik tentang berapa banyak Unpin terikat secara ergonomis? Apakah ini sangat langka? Apakah ini sangat umum? Cukup umum untuk menjadi sakit jika itu adalah rasa sakit untuk mengetik?

Untuk nama yang pendek dan manis, saya pribadi menyukai ide Relocate , tetapi untuk ide yang lebih panjang-dan-lebih-kata-tapi-ok-karena-Anda-tidak-mengetik-sebanyak-saya suka MoveFromPin . Saya pribadi merasa bahwa terlepas dari ergonomi pengetikan nama keduanya lebih baik dari Unpin

Saya ingin tahu, tetapi @cramertj atau yang lainnya apakah Anda merasa ada pegangan yang baik tentang seberapa banyak ikatan Lepas pin muncul secara ergonomis? Apakah ini sangat langka? Apakah ini sangat umum? Cukup umum untuk menjadi sakit jika itu adalah rasa sakit untuk mengetik?

Menurut pengalaman saya, ada dua kasus di mana Unpin sebenarnya muncul di kode pengguna:

  1. Unpin bounds muncul karena Anda benar-benar perlu untuk memindahkan masa depan saat Anda melakukan polling (misalnya hal-hal seperti beberapa API tertentu).
  2. Lebih umum, jika masa depan Anda hanya umum di atas sesuatu selain masa depan, Anda biasanya ingin menambahkan implementasi tanpa syarat dari Unpin , karena tidak masalah jika jenis lain itu Unpin karena Anda tidak pernah sematkan proyek ke mereka.

Contoh kasus kedua adalah jika Anda memiliki beberapa jenis buffer yang Anda gunakan secara umum (misalnya T: AsRef<[u8]> ). Anda tidak perlu menyematkannya untuk mengeluarkan potongannya, jadi Anda tidak peduli apakah itu mengimplementasikan Unpin atau tidak, jadi Anda hanya ingin mengatakan tipe Anda mengimplementasikan Unpin tanpa syarat sehingga Anda dapat mengimplementasikan Future mengabaikan pemasangan pin.

Unpin cukup umum untuk dilihat sebagai ikatan-- select! , StreamExt::next dan kombinator lainnya semuanya membutuhkan tipe yang mereka operasikan menjadi Unpin .

@withoutboats Saya ingin tahu tentang poin 2 Anda di sana; apakah menurut kami impl Unpin adalah sesuatu yang harus diingat orang untuk sering diterapkan? Mirip dengan bagaimana penulis perpustakaan saat ini sering lupa #[derive(Debug)] atau impl std::error::Error untuk jenis kustom mereka, yang membuatnya lebih sulit untuk menggunakan perpustakaan tersebut?

Lepas pin adalah sifat otomatis. Satu-satunya saat Anda akan memiliki jenis yang tidak menerapkan pelepasan pin adalah saat jenis tersebut secara eksplisit menyisih. (Atau berisi bidang yang memilih untuk tidak melepaskan pin).

Saya mengerti bahwa itulah masalahnya. Dan saya berasumsi bahwa sejauh ini itu akan menjadi kasus yang paling umum, itulah sebabnya saya terkejut bahwa @withoutboats bahkan menyebutkan poin kedua. Ini menunjukkan kepada saya bahwa ini mungkin lebih umum daripada yang saya kira (meskipun mungkin hanya ketika menerapkan masa depan Anda sendiri), jadi saya ingin tahu tentang frekuensi kasus penggunaan semacam itu :)

@alexcrichton Saya ingin tahu, tetapi @cramertj atau yang lainnya apakah Anda merasa ada pegangan yang baik tentang seberapa banyak ikatan Unpin yang ergonomis muncul? Apakah ini sangat langka? Apakah ini sangat umum? Cukup umum untuk menjadi sakit jika itu adalah rasa sakit untuk mengetik?

Saya telah menulis posting panjang tentang pengalaman saya mem-porting kode saya ke Futures 0.3 (yang menggunakan Pin ). Anda tidak perlu membacanya, ringkasannya adalah:

Sebagian besar waktu Anda tidak perlu khawatir tentang Unpin sama sekali, karena Unpin diterapkan secara otomatis untuk hampir semua jenis.

Jadi satu-satunya saat Anda perlu khawatir tentang Unpin adalah:

  1. Anda memiliki tipe yang umum dibandingkan tipe lainnya (mis. struct Foo<A> ).

  2. Dan Anda ingin menerapkan API penyematan (misalnya Future / Stream / Signal ) untuk jenis itu.

Dalam hal ini Anda perlu menggunakan ini:

impl<A> Unpin for Foo<A> where A: Unpin {}

Atau ini:

impl<A> Unpin for Foo<A> {}

impl<A> Future for Foo<A> where A: Unpin { ... }

Biasanya itulah satu-satunya situasi di mana Unpin dibutuhkan. Seperti yang Anda lihat, itu biasanya berarti perlu menggunakan Unpin ~ 2 kali per jenis.

Dalam kasus non-kombinator, atau dalam kasus tipe yang tidak menerapkan Future / Stream / Signal , Anda tidak perlu menggunakan Unpin sama sekali.

Jadi saya akan mengatakan bahwa Unpin muncul sangat jarang, dan itu hanya benar-benar muncul dalam situasi membuat Future / Stream / Signal combinators.

Jadi saya sangat menyukai nama seperti MoveFromPin . Memasang pin adalah fitur khusus yang tidak perlu ditangani oleh kebanyakan orang, jadi kita tidak boleh terlalu mengoptimalkan panjang nama.

Saya pikir manfaat kognitif (menghindari negasi ganda) jauh lebih penting daripada menyimpan beberapa karakter dalam situasi yang jarang terjadi.

Terutama karena pemasangan pin sudah cukup sulit untuk dipahami! Jadi jangan membuatnya lebih sulit.

@jonhoo, apakah menurut kami impl Unpin adalah sesuatu yang harus diingat orang untuk sering diimplementasikan? Mirip dengan bagaimana penulis perpustakaan saat ini sering lupa #[derive(Debug)] atau impl std::error::Error untuk jenis kustom mereka, yang membuatnya lebih sulit untuk menggunakan perpustakaan tersebut?

Saya rasa tidak mungkin lupa impl Unpin , karena jika penulis lupa, mereka akan mendapatkan kesalahan kompilator, yang mencegah peti mereka dipublikasikan. Jadi sama sekali tidak seperti #[derive(Debug)] .

Situasi yang dibicarakan @withoutboats hanya untuk orang yang menerapkan Future / Stream / Signal combinators, itu tidak mempengaruhi orang lain (khususnya, itu tidak mempengaruhi pengguna hilir perpustakaan).

(Saya pikir negasi ganda adalah bagian darinya, dan mungkin lebih-negasi-daripada-benar-benar-diperlukan, tapi saya merasa itu bukan keseluruhan cerita (mencoba introspeksi di sini) ... "Lepas pin" itu sedikit , metafora? Tidak langsung? Masuk akal ketika dijelaskan, dan karena "menjepit" itu sendiri sudah menjadi metafora, tidak jelas mengapa otak saya akan bermasalah dengan mengambil lebih jauh dari metafora itu, tetapi, meskipun demikian, otak saya menemukan arti dari "lepas pin" karena alasan tertentu tidak jelas dan sulit dipasang dengan kuat.)

Saya kira Anda benar @cramertj , sebenarnya ini bukan negasi ganda dalam arti biasa, tetapi seperti @alexcrichton dan @glaebhoerl saya terus tersandung olehnya. "UN" sebagai awalan memiliki sangat perasaan negasi-y untuk itu ( "tidak aman", "diimplementasikan" dan seterusnya adalah bagaimana saya biasanya menemukan awalan itu), dan itu meniadakan menjepit di sini, jika hanya sebagai kata kerja.

@withoutboats Saya ingin tahu tentang poin 2 Anda di sana; apakah menurut kami impl Unpin adalah sesuatu yang harus diingat orang untuk sering diterapkan? Mirip dengan bagaimana penulis perpustakaan saat ini sering lupa untuk # [derive (Debug)] atau impl std :: error :: Error untuk tipe khusus mereka, yang membuat lebih sulit untuk menggunakan perpustakaan tersebut?

Benar-benar tidak! Jika pengguna secara manual mengimplementasikan Future yang bersifat generik di masa mendatang, mereka mungkin ingin dapat mengubah status dalam implementasi mendatang tanpa menulis kode yang tidak aman - yaitu, memperlakukan Pin<&mut Self> sebagai &mut self . Mereka akan mendapatkan kesalahan yang menunjukkan bahwa MyFuture<T: AsRef<[u8]>> tidak mengimplementasikan Unpin . Solusi terbaik untuk masalah ini adalah dengan mengimplementasikan Unpin . Tetapi satu-satunya dampak ini adalah pada pengguna yang mencoba mengimplementasikan Future , dan tidak mungkin bagi mereka untuk melupakannya karena kode mereka tidak dapat dikompilasi.

Situasi yang dibicarakan oleh @withoutboats hanya untuk orang-orang yang mengimplementasikan kombinator Future / Stream / Signal, itu tidak mempengaruhi orang lain (khususnya, ini tidak mempengaruhi pengguna perpustakaan hilir).

Saya secara khusus berbicara tentang masa depan manual generik non-kombinator , yang seharusnya hanya memiliki implikasi selimut Unpin bahkan jika obat generik mereka bukan Unpin .

Saya membuat diagram alur untuk pertanyaan "Apa yang harus saya lakukan tentang pemasangan pin saat saya menerapkan masa depan / aliran manual?"

pinning-flowchart

Untuk lebih banyak bersepeda, hari ini saat makan siang saya mendapatkan LeavePin . Ini membawa nada yang sama seperti escape tanpa semantik menyesatkan yang tersirat.

Apakah ada interaksi yang menarik antara impl specialist dan pin, seperti halnya dengan masa pakai?

Substring "spesialis" muncul saat melacak diskusi masalah , tetapi tidak konklusif. Pin RFC atau spesialisasi RFC harus secara eksplisit menyebutkan interaksi ini, baik sebagai "Sudah diverifikasi untuk menjadi OK" atau "penelitian lebih lanjut diperlukan untuk menilai aman".

@vi tidak hanya tidak ada interaksi yang sehat, juga tidak mungkin ada interaksi yang sehat. API pin didefinisikan secara ketat di pustaka standar dan tidak melibatkan fitur bahasa baru, pengguna dapat mendefinisikannya dengan mudah di pustaka pihak ketiga. Jika fitur bahasa tidak benar karena kode perpustakaan ini ada, itu adalah periode yang tidak benar, karena setiap pengguna dapat menulis kode perpustakaan ini hari ini dan itu akan dikompilasi dengan baik.

Jika fitur bahasa tidak benar karena kode perpustakaan ini ada, itu adalah periode tidak sehat, karena setiap pengguna dapat menulis kode perpustakaan ini hari ini dan itu akan dikompilasi dengan baik.

Bukan berarti itu harus ada hubungannya dengan pin ... tapi menurut saya tidak sesederhana itu.

Jika fitur perpustakaan, saat menggunakan unsafe , menggunakan konstruksi bahasa yang perilakunya masih belum ditentukan (misalnya &packed.field as *const _ , atau membuat berbagai asumsi tentang ABI) maka jika perubahan bahasa tambahan membatalkan asumsi dari perpustakaan-perpustakaan itu maka saya pikir itu adalah perpustakaan yang tidak sehat dan bukan bahasa yang berubah. Di sisi lain, jika perubahan bahasa membuat perilaku yang ditentukan menjadi tidak sehat maka itu adalah kesalahan dari bahasa yang berubah. Karenanya, mengompilasi dengan baik bukanlah kondisi yang cukup untuk kesehatan perpustakaan dalam menghadapi perubahan bahasa dan tidak aman.

1 untuk MoveFromPin atau serupa

Jika Anda mengajukan pertanyaan "Kapan saya harus membatalkan implementasi Lepas pin untuk tipe saya sendiri?", Jawabannya akan jauh lebih jelas jika Anda malah bertanya "Kapan saya harus membatalkan penerapan MoveFromPin untuk tipe saya sendiri?"

Sama dengan "Haruskah saya menambahkan Lepas pin sebagai sifat yang terikat di sini?" vs "haruskah saya menambahkan MoveFromPin sebagai ciri yang terikat di sini?"

Tidak memasang pin! Pindahkan

Maaf jika ini disebutkan di suatu tempat, tetapi saya hanya membaca sekilas sejumlah besar diskusi yang ada seputar Pin di sini, dalam masalah implementasi, dan dalam masalah RFC.

Apakah karat akan pernah ada! Saya pasti dapat melihat kasus penggunaan untuk hal semacam itu (sih, saya datang mencari tentang Pin karena saya sedang mencari cara untuk tidak menembak diri saya sendiri dengan tipe yang tidak dapat dipindahkan). Jika jawabannya ya, bagaimana cara berinteraksi dengan Pin? Akankah keberadaan Pin membuatnya lebih sulit daripada sebelumnya!

Periode komentar terakhir, dengan disposisi untuk digabungkan , sesuai ulasan di atas , sekarang selesai .

Seharusnya ada kekhawatiran yang belum terselesaikan seputar penamaan Lepas Pin.

Seperti yang ditunjukkan oleh @RalfJung , # 55992 juga hanya menambahkan sejumlah kecil dokumentasi tambahan yang diminta di https://github.com/rust-lang/rust/issues/55766#issuecomment -438316891 dan lainnya. Tidak tahu bahwa itu alasan untuk belum bergabung.

Mengapa metode drop () saya sekarang mengambil & mut self lagi, bukan Pin.

Nah, drop () sudah tua - itu ada sejak Rust 1.0 - jadi kita tidak bisa mengubahnya. Kami ingin membuatnya mengambil Pin <& mut Self>, dan kemudian jenis Lepas Pin bisa mendapatkan & mut seperti yang mereka lakukan sekarang, tetapi itu adalah perubahan yang tidak kompatibel ke belakang.

Saya bertanya-tanya apakah mungkin menerapkan perubahan ini dengan cara yang kompatibel ke belakang. AIUI sampai kita menambahkan Unpin (dan orang dapat menentukan !Unpin ) semua tipe mengimplementasikan Unpin . Jadi kita bisa menambahkan ciri:

trait DropPinned {
    fn drop(Pin<&mut> self);
}

dan kemudian mengimplikasikan sifat ini untuk semua tipe Unpin , yang sampai orang dapat menyisih adalah semua tipe. Sesuatu seperti:

impl<T> PinDrop for T where T:Unpin + Drop {
    fn drop(Pin<&mut T> self) {
        Drop::drop(self.get_mut());
    }
}

Kemudian kita akan memiliki panggilan insert compiler ke DropPinned::drop daripada Drop::drop . Pada dasarnya ciri DropPinned menjadi lang-item daripada Drop . AFAICS ini akan kompatibel ke belakang jika dan hanya jika mekanisme ini diperkenalkan pada saat yang sama dengan Unpin .

Seharusnya ada kekhawatiran yang belum terselesaikan seputar penamaan Lepas Pin.

@tikue Tidak ada anggota tim libs yang mengajukan masalah dengan rfcbot sebelum atau selama FCP, dan saya tidak yakin argumen apa pun tentang Unpin baru atau baru untuk utas ini, jadi biasanya proses kami akan mempertimbangkan arus penamaan untuk diselesaikan. Tentunya jika seseorang memiliki kekhawatiran, mereka harus angkat bicara, tetapi inti dari kotak centang tim yang diikuti oleh FCP adalah untuk memastikan bahwa semua orang merasa nyaman menstabilkan API seperti yang diusulkan.

@cramertj Saya agak bingung. Beberapa orang telah angkat bicara. Ketika saya meminta referensi tentang di mana lagi argumen tentang penamaan Unpin telah dimunculkan dan diselesaikan, saya diarahkan ke https://internals.rust-lang.org/t/naming-pin-anchor- move / 6864 , yang sejauh yang saya bisa lihat juga ada orang yang mengeluh tentang penamaan Unpin , dan tidak ada argumen tandingan yang nyata. RFC asli di https://github.com/rust-lang/rfcs/pull/2349 juga tidak memiliki banyak alasan mengapa alternatif yang diusulkan untuk Unpin lebih buruk. Bahkan di utas ini, tampaknya satu-satunya argumen balasan yang benar-benar muncul adalah "itu lebih pendek" dan "secara teknis benar". Apakah Anda bisa menunjuk ke diskusi konkret di mana nama-nama alternatif yang lebih mudah dipahami (seperti MoveFromPin ) dibahas dan ditolak?

Saya telah menjelaskan di komentar sebelumnya mengapa saya percaya perspektif baru telah dikemukakan di utas ini. Saya telah mengikuti diskusi API pin cukup dekat sejak awal dan tidak ingat pernah melihat masalah negatif ganda muncul sebelum utas ini.

@tikue Saya telah mengungkit dan melihat masalah negatif ganda Unpin telah diangkat sebagai masalah berkali-kali dan telah diselesaikan secara konsisten demi Unpin . Seperti yang saya katakan sebelumnya, jika seseorang di tim libs ingin mendaftarkan keberatan (terlambat) maka saya akan menjawabnya dengan baik, tetapi mereka semua menandatangani proposal stabilisasi di atas yang jelas tidak menyertakan penamaan Unpin sebagai pertanyaan yang belum terselesaikan: kita telah mendiskusikan alternatifnya, dan FCP ini adalah proses untuk memutuskan bahwa kita siap untuk menstabilkan keputusan yang telah dibuat, termasuk nama Unpin .

@cramertj Bisakah Anda memberikan tautan ke tempat diskusi itu terjadi? Saya tidak meragukan Anda, hanya ingin melihat argumen yang mendukung Unpin , karena saya tidak percaya argumen tersebut diberikan di sini. Seperti yang disebutkan, referensi yang saya berikan sejauh ini tidak memberikan resolusi apa pun tentang penamaan Unpin .

@cramertj +1 untuk @jonhoo 's ask. Jika ada diskusi yang dilakukan tim libs di antara mereka sendiri yang tidak terdaftar di jalur resmi, saya pikir tujuan utama dari diskusi tersebut harus diulangi di sini. Saya pikir bahkan ada aturan resmi bahwa keputusan RFC hanya dapat dibuat berdasarkan argumen yang diketahui publik?

Saya pikir bahkan ada aturan resmi bahwa keputusan RFC hanya dapat dibuat berdasarkan argumen yang diketahui publik?

Yup, itu benar-- dan sebagai catatan, saya bukan anggota tim libs dan karena itu belum hadir untuk diskusi khusus tim libs. Melihat melalui utas RFC dan masalah pelacakan Pin , ada banyak waktu di mana nama Unpin diangkat. Saya tidak melihat ada orang yang secara spesifik mengucapkan kata-kata "negatif ganda", tetapi saya pasti ingat " !Unpin adalah negatif ganda" yang disebutkan sebelumnya, selain aturan API umum tentang sifat penamaan untuk apa yang Anda bisa lakukan dengan mereka, daripada apa yang tidak bisa Anda lakukan (seperti yang saya tunjukkan di atas, saya pikir Unpin sebenarnya mengikuti kedua aturan ini, meskipun menyadari hal itu membutuhkan mendengar "Lepas pin" sebagai kata kerja daripada mendengarnya sebagai kata sifat "not-pin", yang tidak intuitif bagi orang).

@wmanley Itu tidak berhasil, misal impl<T> Drop for Vec<T> akan rusak karena kita tidak memiliki Vec<T>: Unpin . Juga, proposal sepanjang garis ini telah dibuat sebelumnya, bahkan di utas ini . Harap baca diskusi sebelum menjawab. Saya tahu itu meminta cukup banyak, tetapi itu adalah satu-satunya cara untuk menghindari masalah yang sama dijelaskan berulang kali.

Saya pikir bahkan ada aturan resmi bahwa keputusan RFC hanya dapat dibuat berdasarkan argumen yang diketahui publik?

Ini secara informal dikenal sebagai aturan "tidak ada alasan baru" .

Tidak yakin di mana harus memposting ini, tetapi bisakah seseorang melihat di https://github.com/rust-lang/rust/issues/56256 ?

Terkait dengan # 56256, impl<T> From<Box<T>> for Pin<Box<T>> tidak terdaftar di OP sebagai distabilkan, tetapi secara implisit akan menjadi stabil setelah Pin melakukannya. Apakah ada implementasi sifat lain yang tidak sepele dan harus dilihat untuk stabilisasi? (memindai dokumen, semua dokumen lainnya tampaknya merupakan implementasi pendelegasian yang sepele untuk penunjuk yang dibungkus kepada saya).

Kami membicarakan Masalah ini di tim libs hari ini. Pembahasan minggu-minggu terakhir menunjukkan bahwa masih ada beberapa hal yang harus dibenahi terlebih dahulu, khususnya mengenai penamaan Unpin .

Oleh karena itu, kami tidak akan bergerak maju dengan menstabilkan ini untuk saat ini (meskipun demikian FCP).

Akan sangat dihargai jika seseorang dapat mengumpulkan ide-ide di utas ini dan menyiapkan proposal mandiri untuk meningkatkan situasi penamaan.

@Bayu_joo

Akan sangat dihargai jika seseorang dapat mengumpulkan ide-ide di utas ini dan menyiapkan proposal mandiri untuk meningkatkan situasi penamaan.

Apakah ini berarti bahwa tim libs tidak ingin menstabilkan API saat ini sebagaimana adanya? Saya pribadi tidak berpikir ada orang yang datang dengan nama yang lebih baik daripada kumpulan nama saat ini seperti yang diterapkan, jadi saya tidak dapat membuat proposal seperti itu, tetapi saya sangat peduli untuk melihat API ini distabilkan, jadi jika seseorang dari tim libs memiliki nama yang mereka sukai maka: shipit:

Menyematkan ini dengan sekelompok rekan kerja dan @anp menyarankan DePin , yang sebenarnya cukup saya sukai, karena ini menghilangkan konotasi "bukan pin" dari Unpin dan menekankan bahwa ini berbicara tentang sebuah tipe yang dapat menjadi Pin 'd.

@Kimundi dapatkah Anda atau seseorang dari tim libs mendaftarkan "perhatian fcp" secara eksplisit untuk mengeluarkan ini dari FCP dan menjelaskan lebih jelas apa yang dimaksud dengan "beberapa hal yang harus ditangani"?

@rfcbot perhatian penamaan-dari-Lepas pin

Saya tidak yakin apakah ini benar-benar berfungsi setelah FCP dimasukkan, tetapi saya ingin menempatkan masalah pemblokiran formal pada penamaan ciri Unpin . Sifat Unpin kelihatannya sangat penting untuk API, dan "negatif ganda" (seperti yang dibahas di atas) membuat saya berputar setiap kali saya membacanya.

Ada banyak komentar tentang berbagai nama, tapi sayangnya saya belum terlalu senang dengan apa pun. "Favorit" saya masih di sepanjang baris MoveFromPin atau Relocate (tuhan saya ada begitu banyak komentar di sini, saya tidak tahu bagaimana mengulasnya).

Saya pribadi baik-baik saja dengan penamaan Pin itu sendiri serta Pinned untuk ZST yang tidak menerapkan sifat Unpin .

Saya sepenuhnya setuju dengan @alexcrichton bahwa penamaan Unpin adalah poin utama perdebatan di sini. Saya tidak berpikir ada masalah teknis sejauh yang saya bisa lihat tentang fitur yang diusulkan itu sendiri (meskipun ada _are_ banyak komentar, jadi bisa saja melewatkan sesuatu).

Saya masih berpikir Pinned adalah nama yang aneh untuk ZST, karena sesuatu yang mengandung Pinned tidak benar-benar disematkan .. Hanya saja bukan Unpin . PhantomPinned (karena telah diubah namanya menjadi # 55992) memiliki masalah yang sama karena mengacu pada Pin , ketika ZST _really_ sekitar Unpin .

Saya juga masih berpikir dokumen membutuhkan lebih banyak pekerjaan mengingat kehalusan fitur ini, tetapi itu mungkin tidak dihitung sebagai pemblokir.

Juga, @Kimundi , saya senang melihat tim libs bersedia memberikan lebih banyak waktu untuk menyelesaikannya. Ini mungkin tampak seperti bikeshedding yang tidak perlu, tetapi saya (dan orang lain juga tampaknya) merasa cukup penting untuk meningkatkan kemampuan mengajar fitur ini :)

Setuju dengan @jonhoo tentang Pinned masih merasa aneh, dan PhantomPinned tidak menjadi lebih baik (tidak disematkan dengan cara apa pun, bahkan tidak dengan cara hantu). Saya pikir jika kita menemukan nama yang bagus untuk Unpin , maka Pinned secara alami akan berganti nama menjadi Not{NewNameForUnpin} .

Saya benar - PhantomPinned - jenis ini hampir tidak akan PhantomNotUnpin / PhantomNotDePin / PhantomNotMoveFromPin / dll. Tidak akan membuatnya lebih atau kurang umum atau membuat API lebih atau kurang jelas bagi pengguna yang sudah cukup nyaman dengan API untuk menghasilkan penggunaan yang sah untuk PhantomPinned .

Ide singkatnya: trait Move dan ZST Anchor .

Setiap jenis bisa Move , kecuali jika mengandung Anchor yang membuatnya menempel pada Pin .
Saya suka bagaimana Anchor: !Move secara intuitif sangat masuk akal.

Saya tidak menyarankan agar kita menghabiskan waktu secara khusus untuk PhantomPinned , tetapi menurut saya upaya yang rendah untuk tetap berpikiran terbuka, karena mungkin saja apa pun yang dipasang seharga Unpin akan berhasil juga untuk PhantomPinned .

Kami telah menutupi Move dan menjelaskan mengapa itu tidak pantas berkali-kali. Semua jenis dapat dipindahkan hingga disematkan. Demikian pula, Anchor sebelumnya telah disarankan tetapi tidak jelas sama sekali dari nama yang digunakan untuk menyisih dari Unpin ing / Move ing.

@stjepang Saya pikir Move telah dibuang beberapa waktu yang lalu karena sesuatu yang menjadi !Unpin sebenarnya tidak mencegahnya untuk dipindahkan. Hanya jika sebuah tipe di bawah Pin , dan bukan Unpin , Anda "diwajibkan secara kontrak" untuk tidak memindahkannya.

Dalam komentar asli @withoutboats mengatakan:

Pin wrapper memodifikasi pointer untuk "menyematkan" memori yang dirujuknya pada tempatnya

Saya pikir itu aneh bahwa jenis menerapkan Unpin karena nilai tidak "disematkan" - memori. Namun, masuk akal untuk membicarakan nilai-nilai yang "aman untuk dipindahkan". Bagaimana jika kita mengganti nama Unpin menjadi MoveSafe ?

Pertimbangkan sifat UnwindSafe . Ini hanya sifat penanda "petunjuk" dan aman untuk diterapkan. Jika Anda membiarkan nilai !UnwindSafe melewati batas catch_unwind (dengan AssertUnwindSafe ), Anda akan "mematahkan" dengan membatalkan invariannya.

Demikian pula, jika Anda memiliki nilai !Unpin / !MoveSafe , nilai tersebut masih dapat dipindahkan (tentu saja), tetapi Anda akan "merusak" dengan membatalkan referensi mandiri. Konsepnya mirip.

Sifat Unpin hanya berarti MoveSafe . Bagi saya ini bukan tentang nilai yang dapat dipindahkan dari memori di belakang Pin . Sebaliknya, ini tentang nilai-nilai yang tidak akan "rusak" saat Anda memindahkannya.

MoveSafe memiliki masalah yang sama dengan Move - semua nilai jenis apapun dapat dipindahkan dengan aman. Ini hanya menjadi tidak mungkin untuk memindahkan nilai setelah disematkan.

MoveSafe memiliki masalah yang sama dengan Move - semua nilai jenis apapun dapat dipindahkan dengan aman.

Benar, tapi artinya "aman" berbeda, seperti di UnwindSafe . Bagaimanapun, saya akan baik-baik saja dengan Relocate atau apa pun semacam itu.

Untuk meringkas, saya merasa bahwa nama ciri tidak boleh DePin , Unpin , atau apapun dengan "pin" di namanya. Bagi saya, itulah sumber utama kebingungan. Sifat ini sebenarnya bukan "jalan keluar" dari belenggu Pin - sifat tersebut mengatakan bahwa nilainya tidak akan dibatalkan saat dipindahkan.

Saya hanya melihat Pin dan Unpin sebagai hal yang benar-benar terpisah. :)

Saya merasakan kebalikannya;). Ciri ini hanya bermakna sehubungan dengan Pin, yang merupakan satu-satunya jenis yang kami miliki yang secara bermakna mengekspresikan batasan pada kemampuan bergerak nilai yang mendasarinya. Tanpa Pin, Lepas Pin sama sekali tidak berarti.

Saya suka berpikir tentang menyematkan sebagai meletakkan sesuatu di papan pin. Jika Anda melepas pin sebuah benda yang disematkan ke papan, Anda bisa memindahkan benda tersebut. Menghapus pin adalah melepas pin.
Saya suka nama Unpin .

Saya juga dapat melihat caranya! Lepas pin adalah negasi ganda, dan dapat menyebabkan kebingungan. Namun, saya bertanya-tanya seberapa sering Anda perlu menulis !Unpin .

Satu nama lain yang bisa saya temukan untuk Lepas pin adalah Detach . Kembali ke metafora pinboard, Anda tidak akan _Unpin_, tetapi _Detach_ Pin dari objeknya.

Saya rasa saya sangat suka DePin ! Sejauh ini ini adalah favorit saya - ringkas, jelas merupakan kata kerja dan bukan kata sifat, dan !DePin tampaknya cukup jelas juga ("tidak dapat dilepas pinnya").

Saya pikir itu aneh bahwa jenis menerapkan Lepas pin karena nilai tidak "disematkan" - memori.

Nilainya disematkan ke memori. Tetapi nilai juga sangat penting di sini. Menyematkan memori, bagi saya, hanya tentang memastikan bahwa memori tetap dapat diredakan atau lebih, tetapi tidak dilanggar oleh mem::swap . Menyematkan nilai ke memori adalah tentang tidak memindahkan nilai yang disematkan itu ke tempat lain, yang persis seperti itulah Pin .

Saya juga dapat melihat caranya! Lepas pin adalah negasi ganda, dan dapat menyebabkan kebingungan. Namun, saya bertanya-tanya seberapa sering Anda perlu menulis! Lepas pin.

Saya mendengar Anda ketika Anda mengatakan Anda tidak menganggap nama itu membingungkan. Saya, dan banyak orang lain di utas ini menemukan diri kami bingung dengan penamaannya.

Saya tidak memiliki kodenya, tetapi pertama kali saya mencoba menggunakan futures, saya ingin sebuah fungsi mengembalikan impl Future<Output=T> . Saya tidak dapat mengingat apa yang terjadi, tetapi saya segera mendapatkan kesalahan compiler yang mengeluh tentang T dan Unpin. Pertanyaan yang perlu saya jawab adalah "Apakah aman membatasi T hanya untuk Lepas pin". Dan itu membuat saya menatap ke dalam jurang selama sekitar 2 jam yang mengerikan.

"Oh, oke jadi kalau itu maksud Pin. Jadi Unpin artinya .. Box? Kenapa itu sifatnya?"

"Tunggu, impl !Unpin ? Kenapa bukan impl Pin ?"

"Benar, Pin dan Lepas ... tidak berlawanan. Keduanya sama sekali berbeda. Tunggu, lalu apa maksud Lepas Pin lagi? Kenapa disebut begitu?"

"Apa maksud !Unpin ? Bukan ... yang lain, bukan pin? Hrrrgh"

Masih satu-satunya cara ini masuk akal di kepala saya adalah dengan mengganti 'unpin' dengan 'relocatable'. "Jenis tidak dapat direlokasi dalam memori" sangat masuk akal. Namun, meskipun mengetahui apa yang dilakukan Pin , "ketik tidak melepaskan pin" membuat saya bingung.

Mengganti nama Unpin menjadi Relocatable (atau Relocate ) mendapat suara saya 🗳. Tapi saya akan menemukan saran lain yang lebih baik daripada Lepas pin.

Ciri ini hanya bermakna sehubungan dengan Pin, yang merupakan satu-satunya jenis yang kami miliki yang secara bermakna mengekspresikan batasan pada kemampuan bergerak nilai yang mendasarinya. Tanpa Pin, Lepas Pin sama sekali tidak berarti.

Untuk menekankan hal ini - jaminan di sekitar pin sepenuhnya di sekitar perilaku tertentu, bukan tipe . Misalnya, fungsi generator yang menghasilkan () dapat dengan mudah mengimplementasikan FnOnce dengan melanjutkan berulang kali. Meskipun tipe ini mungkin tidak mengimplementasikan Unpin - karena status hasil dapat merujuk pada dirinya sendiri, antarmuka FnOnce (yang bergerak sendiri) sepenuhnya aman karena belum disematkan saat Anda FnOnce it, yang diperlukan untuk membuatnya menjadi status referensi mandiri. Unpin secara khusus tentang jenis perilaku yang dinyatakan aman setelah jenis disematkan (yaitu, memindahkannya), bukan tentang beberapa properti intrinsik dari jenis tersebut.

Ironisnya, saya hanya datang ke sini untuk berkomentar bahwa meskipun penamaan Unpin pasti telah diperdebatkan di masa lalu, perdebatan tentangnya yang saya ingat adalah ketika kami memilih untuk mengganti Move dengan Unpin , yang, ingin saya katakan, merupakan peningkatan yang jelas . Dan seringkali orang baru menyadari kemudian bahwa, sementara desain saat ini merupakan peningkatan yang pasti dari apa yang sebelumnya, masih memiliki beberapa ruang tersisa untuk perbaikan lebih lanjut . Dari arah mana saya datang ini.

Melepas pin secara khusus tentang jenis perilaku yang dinyatakan aman setelah jenis disematkan (yaitu, memindahkannya), bukan tentang beberapa properti intrinsik dari jenis tersebut.

Perilaku saat disematkan adalah properti intrinsik dari tipe tersebut, sama seperti perilaku / invarian saat dibagikan. Saya membahas ini lebih detail di posting blog ini .

@RalfJung kami berbicara melewati satu sama lain. Ada kebingungan Saya melihat banyak jenis referensi mandiri "tidak dapat dipindahkan" - ini tidak akurat, mereka memiliki status tertentu yang dapat mereka masuki di mana mereka tidak dapat dipindahkan, tetapi ketika mereka berada di negara bagian lain, itu sangat aman untuk memindahkannya (dan API kami mengandalkan kemampuan untuk memindahkannya, misalnya untuk menerapkan kombinator padanya atau memindahkannya ke Pin<Box<>> ). Saya mencoba mengklarifikasi bahwa ini bukan kasus bahwa tipe ini "tidak dapat dipindahkan".

Ah, ya, maka saya setuju. Jenis !DePin tidak selalu disematkan , dan jika tidak, ia dapat dipindahkan seperti jenis lainnya.

@cramertj @withoutboats satu hal yang belum saya yakini, apakah kalian menentang penggantian nama Unpin ? Kedengarannya Anda tidak setuju bahwa itu perlu diubah namanya, tetapi saya tidak yakin apakah Anda menentangnya.

Saya pribadi tidak berpikir masalah utama di sini terletak pada nama Unpin dan bahwa "jika kita bisa mengganti namanya semuanya akan intuitif". Meskipun mengganti nama mungkin sedikit membantu (dan Relokasi / DePin tampak bagus di sini ...), menurut saya kerumitan utama berasal dari konsep menyematkan itu sendiri; ini jelas bukan salah satu konsep termudah untuk dipahami atau dijelaskan; bahkan tidak hampir.

Oleh karena itu, saya pikir dokumentasi dari modul core::pin perlu ditingkatkan _significantly_ dan lebih banyak contoh perlu disertakan. Contoh yang baik akan menunjukkan kasus penggunaan kanonis serta penggunaan fungsi dan implementasi yang tidak aman yang tidak tepat.

@alexcrichton Saya tidak menentang penggantian nama, tidak. Saya pikir Unpin sudah baik-baik saja, tetapi saya akan baik-baik saja dengan DePin , itulah sebabnya saya menyarankannya. RemoveFromPin adalah yang paling jelas "benar", tetapi bertele-tele ke titik garam sintaksis, jadi saya pikir saya akan menentang nama itu secara khusus. Saya, bagaimanapun, menentang untuk menunda stabilisasi tanpa batas sampai kami menemukan nama yang disetujui semua orang adalah yang terbaik-- Saya pikir API memiliki beberapa kompleksitas yang melekat yang tidak akan dibuat secara dramatis lebih baik atau lebih buruk karena nama Unpin sifat. Saya benar-benar ingin mendorong stabilisasi segera untuk mencegah lebih banyak churn ke kode, dokumen, dan diskusi sekitar futures_api (sehingga kita dapat mulai menyiapkan potongan untuk menstabilkan futures_api diri). Mungkin kita harus menjadwalkan pertemuan VC penetapan nama khusus sehingga setiap orang yang memiliki pendapat dapat mengajukan solusi mereka dan kita dapat memiliki peluang bandwidth yang lebih tinggi untuk menyelesaikan ini?

Pilihan saya adalah std::pin::Reloc (Relokasi)

Saya memiliki dua situasi yang sangat hipotetis (yah, sebenarnya hanya satu, tetapi dua eksekusi berbeda) yang saya tidak keberatan untuk menyatakan secara eksplisit apakah hal itu diizinkan atau tidak.

Unpin menunjukkan bahwa transisi dari semua status T (di mana T: Unpin ) adalah hal yang sepele (saya harap saya mengingat istilah itu dengan benar dari salah satu entri blog Pin dapat membagikan &mut T .

Jadi mari kita asumsikan saya ingin membuat tipe Woof yang juga selalu memungkinkan untuk transisi dari semua status Woof sementara dalam status tipe yang disematkan ke tipe yang tidak disematkan menyatakan, tetapi tidak sepele untuk melakukannya dan oleh karena itu tidak dapat mengimplementasikan Unpin , apakah akan diizinkan untuk Woof memiliki fungsi seperti fn unpin(self: Pin<Box<Woof>>) -> Box<Woof> ?

Sama untuk tipe Meow yang terkadang hanya memungkinkan untuk transisi dari yang disematkan ke yang tidak disematkan dan fungsi seperti fn unpin(self: Pin<Box<Meow>>) -> Result<Box<Meow>, Pin<Box<Meow>>> .

2 cts saya untuk bikeshedding:

Jika saya mengerti dengan benar, apa yang dimaksud Unpin realy adalah " Pin tidak berpengaruh pada saya".

Bagaimana dengan sesuatu seperti BypassPin atau IgnorePin ?

Jadi mari kita asumsikan saya ingin membuat tipe Woof yang juga selalu memungkinkan untuk transisi dari semua status Woof saat dalam status tipe tersemat ke status tipe yang tidak disematkan, tetapi tidak sepele untuk melakukannya dan oleh karena itu tidak dapat mengimplementasikan Unpin, apakah akan diizinkan Woof memiliki fungsi seperti fn unpin (self: Pin>) -> Kotak?

Ya, itu mungkin saja. Misalnya, jika Woof adalah elemen dari daftar tertaut yang mengganggu, ini bisa menyediakan fungsi untuk menghapus elemen dari daftar, dan menghapus Pin pada saat yang sama (dengan alasan bahwa untuk non -dengan antrean Woof s, kedua jenis kata tersebut setara, jadi kita dapat melepas pinnya).

Relocate memiliki masalah yang sama dengan RePin bagi saya, ini dapat berarti operasi yang memungkinkan untuk memindahkan nilai dari satu lokasi yang disematkan ke lokasi lain, tidak melepas nilai sepenuhnya. Ini memiliki konotasi yang kurang kuat dibandingkan dengan RePin , tetapi masih tampak sedikit membingungkan.

ini dapat menyiratkan operasi yang memungkinkan untuk memindahkan nilai dari satu lokasi yang disematkan ke lokasi lain, tidak melepas nilai sepenuhnya.

Meskipun bukan itu yang dimaksud dengan sifat ini, ini juga tidak sepenuhnya salah: Untuk sebagian besar kasus penggunaan, memindahkan nilai dari satu lokasi yang disematkan ke lokasi lain sama berbahaya seperti menggunakannya secara bebas. Sebenarnya, mengingat siapa pun dapat membuat Pin<Box<T>> , saya bahkan tidak mengerti mengapa Anda membuat perbedaan mendasar di sini.

Untuk sebagian besar kasus penggunaan, memindahkan nilai dari satu lokasi yang disematkan ke lokasi lain sama mengerikannya dengan menggunakannya secara bebas.

Ya, itulah mengapa memiliki sifat yang menambahkan operasi itu ke suatu tipe bisa berguna (ini tidak bisa menjadi sifat penanda seperti Unpin karena mungkin perlu melakukan hal-hal seperti memperbarui referensi internal). Saya tidak mengusulkan agar kami menambahkan sesuatu seperti ini sekarang, hanya saja itu adalah sesuatu yang saya lihat akan diberikan di masa mendatang (baik dalam std atau pihak ketiga) yang dapat berakhir dengan tumpang tindih nama yang membingungkan.

Saya tidak mengetahui kasus penggunaan yang kuat untuk itu sekarang, tetapi saya telah berpikir untuk menggunakan sesuatu seperti itu dengan koleksi yang disematkan.

Ok jadi inilah beberapa pemikiran. Awalnya saya bertanya-tanya apakah kita bisa memiliki nama seperti PinInert atau PinNoGuarantees karena itu juga deskripsi, tetapi memikirkan bahwa yang saya inginkan adalah sifat yang menggambarkan tindakan sebagai lawan dari properti, atau setidaknya membuatnya lebih mudah untuk dipikirkan di kepala saya.

Satu masalah dengan Unpin (Saya tidak yakin mengapa) adalah bahwa saya tidak dapat memahami maksud yang dimaksud adalah "tindakan menghapus dari pin, melepas pin, aman dilakukan ". Sifat sebagaimana adanya menyampaikan tindakan "tindakan melepas pin" tetapi saya tidak bisa memahami hal itu saat membacanya. Aneh rasanya memiliki Pin<T: Unpin> karena jika "lepas" mengapa ada di Pin?

Saya ingin tahu apakah nama seperti CanUnpin bisa berfungsi? Banyak dari ini bukan tentang jaminan keras dengan satu atau lain cara (menerapkan Unpin tidak berarti Anda akan menghapusnya dari pin, itu hanya berarti Anda dapat menghapusnya dari pin). Bagaimana kedengarannya? Apakah CanUnpin cukup dapat dibaca oleh orang lain? Cukup pendek?

(memiliki awalan Can menyampaikan kata kerja kepada saya dengan lebih mudah juga, dan dikatakan Anda dapat menghapusnya dari pin tetapi Anda tidak selalu akan selalu melakukannya).


Sebagai garis singgung lain yang tidak terkait, satu hal yang lupa saya kemukakan sebelumnya (maaf tentang itu!) Adalah saya tidak berpikir bahwa semua metode di atas harus menjadi metode yang melekat. Kami sudah memiliki banyak bug di sekitar metode inferensi dan bentrok, dan menambahkan nama yang sangat umum seperti as_ref dan as_mut pada jenis yang juga menerapkan Deref sepertinya menjadi masalah menunggu untuk terjadi.

Apakah operasi ini terjadi cukup umum untuk membenarkan lokasi berisiko untuk menempatkannya? (secara inheren) Atau apakah mereka cukup jarang digunakan sehingga rute aman dari fungsi-fungsi terkait dapat dipertimbangkan?

Karena saya tampaknya memiliki skin dalam game ini sekarang: CanUnpin sepertinya sangat dekat dengan saya dengan Unpinnable atau yang serupa, dan kesan saya selalu bahwa komunitas tidak menyukai pengubah semacam itu di nama sifat, karena sebagian besar sifat mendeskripsikan tindakan yang dapat dilakukan oleh tipe tersebut. Implikasinya sendiri adalah "bisa" atau "-able" yang tersirat dalam pengertian itu. Apa pun yang diputuskan (dan namanya tidak menjadi masalah sejauh yang dinyatakan di sini IM-not-so-HO - sangat sedikit pengguna yang mungkin harus mengetik ini), saya akan mendorong semua orang untuk merasakan urgensi untuk menyelesaikan pertanyaan di sini. Saya senang dengan stabilisasi ini, dan saya tahu banyak orang yang menyukainya!

@alexrichard

Satu masalah dengan Unpin (Saya tidak yakin mengapa) adalah bahwa saya tidak dapat memahami maksud yang dimaksud adalah "tindakan menghapus dari pin, melepas pin, aman dilakukan ".

Bagaimana jika Anda menganggap T: Unpin sebagai " T kebal terhadap Pin "? Kemudian jika Anda memiliki Pin<T: Unpin> itu berarti kita memiliki nilai di dalam Pin yang kebal terhadap pin sehingga pin di sini secara efektif diperdebatkan.

Atau dengan kata lain: Unpin menetralkan Pin . Sejujurnya, setelah begitu banyak diskusi saya telah menginternalisasi ini dan sekarang masuk akal. 😆

Banyak dari ini bukan tentang jaminan keras dengan satu atau lain cara (menerapkan Unpin tidak berarti bahwa Anda akan menghapusnya dari pin, itu hanya berarti Anda _dapat_ menghapusnya dari pin).

Sebuah tandingan untuk ini adalah sifat Send . Ini tidak berarti bahwa Anda akan mengirimkan nilainya, itu hanya berarti Anda dapat mengirimkannya.

@anp Saya setuju bahwa CanUnpin bukanlah nama yang bagus, saya berusaha melakukan yang terbaik untuk menemukan nama yang lebih baik! Tampaknya sedikit yang masih merasa ini perlu diganti nama meskipun karena semua saran tampaknya ditolak karena pada dasarnya alasan yang sama saya merasa seperti Unpin perlu diganti nama di tempat pertama.

Juga sebagai pengingat, setiap stabilisasi mengendarai kereta seperti semua perubahan lainnya, dan dengan rilis minggu depan ini pasti tidak akan masuk ke rilis itu dan selanjutnya akan menjadi kandidat untuk rilis berikutnya. Itu berarti kita punya waktu 7 minggu, hampir dua bulan, untuk mendaratkan semua ini untuk memastikannya masuk secepatnya. Meskipun saya setuju bahwa urgensi itu perlu, itu hanya “jangan lupakan tentang urgensi ini”, bukan “mari selesaikan ini sebelum Senin”.

@stjepang Saya, juga, telah terbiasa menjadi Unpin sekarang setelah terlalu memikirkannya! Semua nama alternatif pada saat ini tampak kurang bersemangat, jadi saya sampai pada titik di mana saya akan puas dengan dokumentasi yang lebih baik. Idealnya saya ingin menemukan seseorang yang tidak tahu banyak tentang Pin apis untuk membaca dokumentasi tersebut setelahnya, meskipun, untuk mengecek ulang itu cukup untuk belajar.

Saya juga ingin melanjutkan dan secara resmi memblokir stabilisasi pada dokumentasi yang ditingkatkan, karena ini terasa sangat penting untuk masalah ini.

@rfcbot perhatian meningkatkan-dokumentasi

Secara konkret yang saya rasa membutuhkan dokumentasi yang lebih baik adalah:

  • Prosa lebih lanjut tentang setiap metode tentang mengapa itu aman dan / atau mengapa tidak aman. Misalnya kontrak P DerefMut implementasi "berperilaku wajar" tidak didokumentasikan pada Pin::new_unchecked .
  • Setiap fungsi unsafe harus memiliki contoh kode mengapa tidak aman, atau setidaknya penjelasan yang jelas tentang urutan langkah yang bisa salah.
  • Saya merasa dokumen modul dapat menjelaskan lebih detail lebih dari sekadar apa itu Pin dan apa artinya. Saya pikir mereka akan mendapatkan keuntungan dari informasi seperti "bagaimana ini bukan tipe tidak bergerak umum tetapi bentuknya" atau "bagaimana Pin digunakan dalam praktik, misalnya dengan kontrak berjangka".
  • Saya ingin melihat contoh dengan obat generik dan Unpin baik dalam dokumentasi atau contoh kode. Misalnya kedengarannya banyak kombinator di masa depan harus menangani ini, dan demikian pula beberapa kombinator secara khusus memerlukan ini. Beberapa contoh kasus penggunaan bagaimana seseorang bekerja dengan obat generik dan bagaimana mereka bermain dapat membantu memahami Unpin cukup banyak.

Saya juga penasaran apakah orang lain memiliki item nyata yang dapat ditindaklanjuti untuk ditambahkan ke dokumentasi juga!

Selanjutnya saya juga ingin memblokir secara resmi self -question dengan as_ref , tapi saya rasa ini akan cepat diselesaikan. (sekali lagi maaf karena tidak ingat untuk membicarakan ini lebih awal)

@rbot menyangkut metode mandiri

Ini mengusulkan as_ref , as_mut , get_ref , get_mut , into_ref , dan set untuk semua menjadi metode di Pin jenis. Proposal menyebutkan bahwa kami tidak melakukan ini untuk petunjuk cerdas karena bentrokan metode, tetapi mengutip pengalaman yang menunjukkan bahwa Pin API yang diterapkan hari ini tidak konsisten dan seringkali berakhir begitu saja.

Nama metode ini, bagaimanapun, adalah nama yang sangat pendek dan manis dan cukup umum ditemukan di seluruh ekosistem. Tim libs telah mengalami serangkaian bug yang tidak pernah berakhir di masa lalu di mana kami menambahkan implementasi sifat dan semacamnya dan ini menyebabkan bentrokan dengan metode sifat yang ada di berbagai peti. Metode-metode ini tampaknya berisiko tinggi karena namanya. Selain itu, tidak jelas apakah kami dapat menambahkan lebih banyak metode ke Pin di masa mendatang karena meskipun nama-nama tersebut sekarang akhirnya berhasil, nama masa depan yang ditambahkan memiliki risiko benturan yang tinggi.

Saya hanya ingin memastikan bahwa kita memikirkan kembali perbedaan ini dari konvensi, saya secara pribadi sangat khawatir tentang konsekuensinya dan saya pikir akan sangat bagus jika kita dapat menemukan jalan tengah yang akan menghindari bahaya ini.

Dan sementara saya melakukannya, satu hal terakhir yang saya perhatikan, dan sekali lagi saya pikir ini akan cukup cepat untuk diselesaikan

@ rumahkotak-kotak-pin-pin

Apakah nama Box::pin telah dipertimbangkan untuk Box::pinned ? Dengan adanya Pinned dan / atau PhantomPinned sepertinya akan rapi jika nama bisa cocok dengan tipe yang dikembalikan!

@alexcrichton Apakah ada sesuatu yang secara khusus meyakinkan Anda terhadap MoveFromPin sebagai opsi ? Saya melihat Anda menyukai hal itu sebelumnya (dan banyak orang sepertinya menyukainya juga). Sebagai catatan, keberatan langsung yang dapat saya ingat, atau dengan cepat ditemukan dengan Ctrl + F-ing, adalah bahwa "nama yang merupakan frasa utuh ... akan menjadi sangat tidak otomatis" (@withoutboats) dan "terlalu bertele-tele" ( @jamur_kejang).

Saya harus mengakui bahwa motivasi dalam nada "Saya telah terbiasa ... sekarang setelah terlalu memikirkannya" membuat saya agak tidak nyaman. Manusia bisa terbiasa dan merasionalisasi post-hoc pada dasarnya apa saja. Tidak peduli apa namanya, akan menjadi kejutan besar jika kita akhirnya tidak terbiasa dengannya. (Inilah alasan utama mengapa kami memilih nama yang jelas -suboptimal seperti existential type sebagai sementara dalam kasus lain, untuk mencoba menghindarinya menjadi permanen.)

Secara tidak sengaja mengistimewakan perspektif pengguna berpengalaman (yang mana kita semua!) Atas orang lain yang akan datang dengan otak yang lebih segar adalah jenis kesalahan yang menurut saya kita perlu selalu waspada terhadap pembuatan, sesulit itu .

Meskipun ini jelas bukan gaya std lib, saya juga merasa seperti CanUnpin entah bagaimana membuatnya lebih jelas bagaimana bagian tertentu itu cocok dengan yang lain.

Tidak mungkin untuk menemukan nama yang menjelaskan arti dari Unpin bagi seorang pemula tanpa membaca dokumentasi. Send dan Sync juga sulit dipahami oleh pemula, tetapi mereka terlihat bagus dan ringkas, serta Unpin . Jika Anda tidak tahu apa arti nama-nama ini, Anda harus membaca dokumen mereka.

@valff Memang benar, namun ada beberapa orang yang telah membaca dokumen dan memahami cara kerja pin, namun nama Unpin masih menyebabkan mereka mengalami kesulitan mental yang signifikan, sedangkan nama lain menyebabkan lebih sedikit.

@glaebhoerl oh maaf untuk menjelaskan. Saya pribadi lebih menyukai MoveFromPin atau CanUnpin daripada Unpin . Hanya mencoba membantu mencapai kesimpulan!

Saya mencoba memahami proposal saat ini, mungkin laporan kemajuan semacam ini dapat memberi penerangan tambahan pada penamaan juga.

  • Memperluas jaminan Pin ke alamat yang stabil hingga Drop memberikan persyaratan tambahan pada pembuat Pin . Saya akan merasa berguna jika prasyarat yang diperlukan untuk meminta unsafe fn new_unchecked(pointer: P) -> Pin<P> disebutkan secara langsung. Memahami bagaimana Pin dapat dibuat sangat membantu dalam memahami konsep mereka, imo.
  • Ringkasan yang disebutkan dalam masalah pelacakan, diawali dengan we agreed that we are ready to stabilize them with no major API changes. , berisi banyak api lama. Pada saat yang sama, ini juga berisi banyak wawasan tentang Drop dan proyeksi pin yang relevan. Ini juga berisi rumusan eksplisit tentang jaminan tambahan sebagaimana dimaksud dalam butir satu yang tidak ditemukan dalam laporan ini. Campuran informasi lama dan baru ini agak membingungkan, pertimbangkan untuk memindahkan semua informasi ke dalam masalah ini atau menunjukkan paragraf yang sudah ketinggalan zaman.
  • Karena jaminan tambahan disebut sebagai slight extension , saya berharap ada semacam cara untuk tidak ikut serta. Karena penyematan sekali membawa status tipe pada penunjuk tersebut hingga dilepaskan, beberapa cara untuk kembali dari status tipe ini ke status 'normal'. Sebenarnya, itulah yang saya pikir Unpin lakukan pada awalnya tapi saya pikir Unpin sebenarnya sedikit lebih kuat. Dikatakan bahwa status tersemat dapat dengan bebas diubah menjadi status unpinned, sesuka hati. Tidak masalah jika antarmuka saat ini minimal dalam hal ini, tetapi Unpin dapat dikacaukan dengan operasi pada jenis yang menghapus beberapa invarian dalam yang memerlukan status pin (seperti versi lunak Drop ) .

Klarifikasi: Saya pribadi lebih menyukai MoveFromPin daripada nama lain tetapi bisa dibilang artifisial dan kikuk.

Item utama yang dapat ditindaklanjuti yang dapat ditindaklanjuti yang terlintas dalam pikiran, selain perbaikan dokumentasi yang sudah diminta oleh @alexcrichton , akan menjelaskan alasan di balik aturan bidang untuk proyeksi pin di map_unchecked dan map_unchecked_mut . Sesuatu di sepanjang baris:

Pin berjanji untuk tidak memindahkan data yang dirujuk hingga dijatuhkan. Karena bidang dari struct dihapus setelah struct yang berisi, status pin mereka melampaui Drop implementasi dari struct itu sendiri. Memproyeksikan ke sebuah field berjanji untuk tidak berpindah darinya di dalam structs destructor.

Bagaimana dengan nama ElidePin untuk sifat penanda turunan otomatis?

Ini akan menangkap bahwa jenis selalu dapat diperlakukan seolah-olah atau berperilaku seolah-olah tidak disematkan. Dan !ElidePin tampaknya cukup jelas juga, meskipun itu mungkin subjektif.

Penanda standar juga tidak memiliki nama yang sempurna untuk memahami penyematan. Pinned tampaknya membangkitkan gagasan bahwa struct yang berisi itu sendiri disematkan tetapi penyematan berlaku untuk pointer dan hanya setelah tindakan eksplisit. Ini tidak terlalu penting tetapi juga tidak signifikan, terutama karena ini bisa menjadi tipe yang pertama kali ditemukan dalam implementasi untuk tipe referensi sendiri.

Penentangan umum saya terhadap MoveFromUnpin / RemoveFromUnpin hanyalah karena mereka terlalu bertele-tele dan akan menurunkan ergonomi implementasi manual Future . CanUnpin / DePin keduanya tampak baik-baik saja bagi saya-- Saya berharap lebih jelas bahwa Unpin mengikuti pola Read / Write / etc. tetapi tampaknya itu tidak intuitif bagi orang-orang jadi saya akan memberi +1 pada apa pun yang membuat ini lebih jelas tanpa terlihat seperti garam sintaksis.

Saya setuju NotWhateverUnpinBecomes mungkin adalah nama terbaik untuk Pinned . Yang mengatakan, Adhere berarti memperhatikan dan tetap berpegang pada. : sedikit_muka_senyum:

CanUnpin / DePin keduanya tampak baik-baik saja bagi saya-- Saya berharap lebih jelas bahwa Lepas pin mengikuti pola Baca / Tulis / dll

Saya pikir salah satu hal yang membuat Unpin sulit, tidak seperti Read adalah bahwa ini adalah ciri penanda. Read mudah dimengerti karena ada metode Read::read - semua yang perlu Anda ketahui ada di trait . Jika x adalah Read Saya mengerti bahwa saya dapat menelepon x.read() - sama halnya dengan write untuk Write , dll. Lebih sulit untuk menjelaskan bahwa X mengimplementasikan Unpin berarti Pin<Ptr<X>> mengimplementasikan DerefMut - yang berarti Anda dapat memperlakukannya seolah-olah hanya X .

Baca mudah dipahami karena ada metode Read :: read

Jika saja kita dapat menambahkan metode yang selalu berlaku di auto trait definisi + GAT, kita dapat memiliki Unpin::unpin - fn unpin<P: DerefFamily>(self: Pin<P::Deref<Self>>) -> P::Deref<Self> ). ..... setelah dipikir-pikir, saya tidak berpikir itu akan membuat orang kurang bingung;)

(pada catatan yang lebih serius, saya mendukung Pin::unpin untuk beralih dari Pin<P<T>> menjadi P<T> )

Saya akan mendukung Pin :: unpin untuk beralih dari Pin

> ke P

Ini membingungkan dua istilah di kepala saya, seperti nama itu sendiri. unpin terdengar sangat mirip dengan membalikkan jaminan status tipe, untuk perbandingan yang seolah-olah ada metode fn unborrow(&'_ T) atau fn unmove(??) . Karena pin memberikan jaminan sampai beberapa memori yang mewakili sebuah tipe adalah Drop::drop ed, kami tidak benar-benar membalikkan keadaan, tipe tersebut hanya menjamin bahwa semua representasi lain memberikan jaminan yang setara dan dengan demikian kami dapat mengabaikan ini . Ini juga merupakan perbedaan utama yang saya lihat antara ciri-ciri penanda dan sesuatu seperti io::Read . Satu mengaktifkan operasi untuk kompilator atau bahasa, sementara yang lain mengaktifkan operasi untuk pemrogram.

Selain itu, ini adalah poin utama yang saat ini tidak dapat disajikan secara akurat hanya dengan menggunakan pengetikan yang benar. Untuk memanggil operasi unpin membuatnya terdengar seperti ada fungsi sebaliknya pin . Ini menjadi fungsi yang juga sedikit salah mengisyaratkan bahwa operasi pelepasan pin semacam itu terikat pada pekerjaan komputasi, misalnya into_pointer() akan lebih baik dalam hal ini dengan juga mengikuti konvensi penamaan yang lebih mapan.

Terakhir, saya pikir ada potensi untuk tipe yang secara khusus memiliki fungsi unpin dengan pekerjaan komputasi. Jenis dengan invarian dalam yang sangat khusus mungkin dapat 'memperbaiki' keadaan dalamnya sedemikian rupa sehingga ia dapat menawarkan antarmuka fn unpin(self: Pin<&'a mut T>) -> &'a mut , di mana ia rela kehilangan semua jaminan Pin untuk seumur hidup 'a . Dalam hal ini, kedua poin di atas tidak berlaku lagi. Fungsi seperti itu dapat dibayangkan seolah-olah memiliki efek yang setara dengan menjatuhkan dan merekonstruksi di lokasi memori yang sama (sehingga benar-benar menghapus status tipe). Dan ini mungkin melibatkan komputasi, misalnya dengan memindahkan beberapa referensi mandiri ke dalam alokasi dinamis.

Akan sangat disayangkan jika nama yang membingungkan juga akan mempersulit desainer dan pelaksana perpustakaan untuk memilih nama yang tidak membingungkan, dengan menggabungkan kedua ide ini.

Penentangan umum saya terhadap MoveFromUnpin / RemoveFromUnpin hanya karena mereka terlalu bertele-tele dan akan menurunkan ergonomi implementasi manual Future.

Saya rasa itu tidak benar, terutama untuk MoveFromPin , yang tampaknya masuk akal untuk saya ketik - dan dengan segala jenis pelengkapan otomatis yang cerdas atau bodoh, masalahnya sebagian besar tidak ada.

Salah satu bagian penting dari ergonomi harus juga keterbacaan dan pemahaman kode. Rust sudah mendapatkan sedikit kritik di masa lalu karena menyingkat hal-hal secara agresif ( fn , mut , dll), yang membuat beberapa kode lebih sulit untuk dibaca. Untuk hal-hal yang untuk konsep yang bahkan lebih rumit untuk dipahami dan yang memenuhi tujuan khusus bagi sebagian besar pengguna, penggunaan nama yang lebih verbose dan deskriptif harus diterima sepenuhnya.

@rfcbot menyelesaikan penamaan-dari-Lepas pin

Oke, saya sudah merebus cukup lama sekarang dan juga berbicara dengan @withoutboats secara langsung tentang hal ini. Saya menyadari bahwa sekarang saya secara pribadi merasa nyaman setidaknya dengan nama Unpin sebagai ciri penanda. Akibatnya, saya akan menghapus keberatan pemblokiran (meskipun jika orang lain di tim libs merasa berbeda, beri tahu kami!)

Alasan utama mengapa saya sampai pada Unpin pada dasarnya adalah apa yang telah dikatakan @cramertj di atas , itu adalah nama paling idiomatik untuk sifat ini yang dapat kami temukan. Semua nama sifat lain yang saya lihat diusulkan tidak memenuhi standar idiomatik yang sesuai dengan Unpin (atau setidaknya menurut saya).

Meskipun saya masih percaya ada nama yang lebih baik untuk "Saya baru saja melihat nama dari sifat ini dan saya ingin tahu apa fungsinya", saya rasa itu bukan masalah yang tepat untuk diselesaikan di sini. Jelas bagi saya pada saat ini bahwa kita tidak dapat, setidaknya untuk saat ini, menemukan nama lain untuk sifat ini yang juga idiomatis, tetapi kita beralih pada nama sifat yang memecahkan masalah yang berbeda. Memahami Unpin sama seperti Send dan Sync , dokumentasi perlu dibaca untuk memahami sepenuhnya apa yang terjadi.


Sebagai poin klarifikasi lain, saya mencantumkan beberapa "keberatan yang memblokir" tetapi itu lebih banyak item TODO daripada memblokir keberatan itu sendiri. Saya hanya tidak memiliki cara yang bagus untuk menavigasi utas yang begitu panjang! Dalam hal itu saya pikir tidak apa-apa untuk PR stabilisasi untuk diposting kapan saja sekarang dengan FCP telah berakhir selama seminggu atau lebih sekarang. Poin terakhir tentang diri / pin / pin dapat didiskusikan secara singkat di sana (jika perlu, mereka dapat ditinggalkan seperti proposal di atas).

Dokumentasi menurut saya khususnya bukanlah prasyarat untuk stabilisasi dalam kasus ini. Kami memiliki siklus penuh (6 minggu) untuk menambahkan dokumen sebelum jenis ini mencapai stabil dan kami punya waktu lebih lama untuk menopang dokumentasi di sini sebelum kisah async / await lengkap mencapai stabil. Banyak sekali waktu untuk meningkatkan apa yang ada sekarang, dan apa yang ada sekarang sudah cukup berguna!

Apa artinya "idiomatik" di sini? Apa yang tidak otomatis tentang Reloc[ate] , Escape , Evade , Pluck , atau Roam ? Mereka semua adalah kata kerja, dan tidak ada satupun yang dapat disalahartikan sebagai memiliki masalah negatif ganda.

@alexcrichton Apakah ada alasan mengapa Unpin dianggap lebih idiomatis daripada Depin atau DePin ?

Saya pikir Depin adalah alternatif yang sangat solid, dan itu tidak menyebabkan saya mengalami kesulitan mental yang sama seperti Unpin .

Salah satu alasan sederhananya adalah depin bukanlah sebuah kata dan lepas pin adalah. Secara pribadi, saya tidak kesulitan memahami Unpin . Saya pikir itu cocok dengan penamaan ciri penanda lainnya.

@jimmycuadra Ada banyak nama di Rust yang bukan kata-kata "asli", termasuk di stdlib.

Saya akan terkejut jika itu dianggap sebagai alasan penting untuk memilih satu nama di atas nama lainnya.

@Pauan Itu adalah alasan yang signifikan. Sebagai penutur asli bahasa Inggris, Depin terdengar seperti kami lupa bahwa kata untuk melepas pin ada dan mencoba membuatnya. Tampaknya sangat salah bagi saya secara tata bahasa: kata bahasa Inggris untuk "depinning" adalah "unpinning."

Sebuah analogi yang baik adalah jika kita memiliki API yang mengatakan "delock" bukan "unlock".

@jaredr oleh "idiomatic" Maksud saya mengikuti konvensi mapan dari perpustakaan standar sudah seperti (disebutkan sebelumnya) Read dan Write sifat. Kami memiliki konvensi nama yang tidak bertele-tele, kata kerja, singkat jika memungkinkan, dan sesuai untuk situasi.

Nama-nama seperti yang Anda sarankan semuanya mungkin, tetapi Unpin (atau setidaknya saya rasa) adalah yang paling sesuai untuk tindakan khusus ini (jaminan "Anda dapat melepas pin jenis ini"). Yang lain, sementara sinonim longgar Unpin , saya pikir sebagian besar hanya mengganti nama dari kata "lepas pin" dan terkadang tidak menyampaikan hubungan yang sama dengan Pin sebagai Unpin tidak.

@Pauan Saya setuju dengan @withoutboats bahwa Depin tidak terdengar seperti jives dan juga Unpin .

@aturon mencatat di https://github.com/rust-lang/rfcs/pull/2592#issuecomment -438873636 bahwa:

Penggunaan Pin tidak lebih merupakan detail implementasi daripada pilihan &self versus &mut self ; dalam jangka panjang, kemungkinan Pin itu sendiri akan menjadi mode referensi terpisah dengan dukungan bahasa. Dalam semua kasus ini, apa yang sedang disampaikan dalam tanda tangan adalah izin yang diberikan kepada callee, dengan Pin melarang pemindahan referensi.

Tampaknya ini mengacu pada tipe asli &pin atau semacamnya ... tapi saya tidak tahu bagaimana kotak ini dengan Pin<&mut T> dan semacamnya. Dalam percakapan saya dengan @withoutboats dan khususnya @cramertj, mereka sama sekali tidak yakin tentang gagasan mode referensi terpisah dengan dukungan bahasa dan bagaimana kami bisa sampai di sana dari Pin<T> .

Sebelum menstabilkan pin , sebaiknya rekonsiliasi pandangan ini untuk memastikan bahwa kita berada di halaman yang sama. infrastruktur penting ini; jadi saya terutama ingin Aaron mengembangkan ini dan untuk perahu dan Taylor untuk kemudian ditimbang.

Yang lain, sementara sinonim lepas dari Lepas pin, saya pikir sebagian besar hanya mengganti nama dari kata "lepas pin" dan terkadang tidak menyampaikan hubungan yang sama dengan Pin seperti Lepas Pin.

@alexcrichton ini sebenarnya hal yang baik, menurut saya? Seperti Send untuk memindahkan / menyalin (=) operasi, Sync untuk meminjam (&) operasi. Mungkinkah koneksi seperti itu sebenarnya menyebabkan lebih banyak kebingungan?

@ crl0710 mungkin! Saya tidak yakin saya akan setuju dengan koneksi seperti itu meskipun saya sendiri. Send dan Sync lebih banyak tentang apa yang mereka aktifkan ("mengirim" tipe ke utas lain dan "menyinkronkan" akses ke utas), dan ketika menamainya kami tidak mencoba untuk hindari menamainya dekat dengan satu operasi atau lainnya

@alexcrich persis! jadi mungkin sifat ini juga harus tentang apa yang memungkinkannya. ("bergerak (Kata kerja di sini) dari Pin ). Saya bukan penutur asli bahasa Inggris, tapi menurut saya "membongkar" dari pin itu sedikit ... aneh?

@ crlf0710 Tapi apa yang mengaktifkan sifat itu bukanlah <moving> dari Pin, itu <moving out of a Pin> . Masalah dengan move dan sinonim untuk move adalah bahwa sifat tersebut menyiratkan sifat mengontrol kemampuan tipe untuk bergerak sama sekali, yang tidak dilakukannya. Hubungan dengan Pin sangat penting untuk memahami apa yang sebenarnya dilakukan oleh sifat tersebut.

Jadi, nama yang paling idiomatis untuk sifat ini adalah kata kerja yang berarti "keluar dari peniti", di mana kata "Lepas pin" adalah yang paling jelas bagi saya. Berikut definisi Wiktionary tentang "lepas pin":

  1. Untuk membuka dengan melepas pin.
  2. (Transitif, komputasi, antarmuka pengguna grafis) Untuk melepaskan (ikon, aplikasi, dll.) dari tempat sebelumnya disematkan.

@withoutboats terima kasih telah menjelaskan! Sebenarnya saya pikir saya dapat menerima nama Unpin atau nama apa pun yang akhirnya diputuskan oleh tim karat, saya tidak ingin memblokir stabilisasi jenis Pin sama sekali, dan saya benar-benar memahami kekhawatiran tentang "pemindahan" dll.

Rasanya hanya ada sedikit "pengulangan" di suatu tempat. dan saya harus meyakinkan diri saya sendiri: itu tidak berarti "tidak dapat diubah", tetapi sebaliknya. Saya kira setelah beberapa waktu saya akan terbiasa jika itu keputusan akhir.

Pada saat yang sama izinkan saya memberikan saran terakhir saya: sebenarnya menurut saya kata kerja Detach disebutkan di atas juga cukup bagus, meskipun agak terlalu umum. Seperti yang saya katakan, saya bukan penutur asli, jadi saya tidak bisa berbicara untuk orang lain. Tolong anggap saja sebagai ide kecil.

Saya berpikir tentang proyeksi disjoint yang aman, dan muncul dengan ide yang memungkinkannya. Ini adalah makro untuk menyimulasikan pencocokan terhadap nilai l yang bisa berubah yang disematkan. Dengan makro ini kita bisa menulis

pin_proj! { let MyStruct { field1, field2 } = a_pinned_mutable_reference; }

untuk mendekomposisi Pin<&mut MyStruct> menjadi referensi yang bisa diubah yang disematkan ke bidang.

Untuk membuat ini aman dan dapat digunakan, kita membutuhkan dua hal lain:

  • Jenis Kite untuk menandai bidang "selalu- Unpin "
  • Hasilkan Unpin tidak aman

Yang terakhir diperlukan untuk keamanan proyeksi. Tanpa ini, kita dapat mendefinisikan " Kite dengan proyeksi tersemat" dengan aman, yang sebenarnya salah.

Dengan pemikiran ini, saya mengusulkan untuk membuat Unpin tidak aman sebelum stabilisasi untuk meninggalkan ruang untuk operasi berguna lainnya agar aman.

@qnighy Ada kemungkinan untuk suatu tipe melanggar jaminan penyematan dalam implementasi Drop , yang membuat Drop sama kuatnya dengan Unpin . Membuat Unpin tidak aman tidak membuat kode tambahan menjadi aman, karena Drop juga aman, dan tidak dapat diubah. Kami telah banyak membicarakan hal ini tentang masalah pelacakan, dan itu telah disebutkan di utas ini juga.

Pada dasarnya, proyeksi pin tidak dapat dibuat aman tanpa kemampuan untuk menegaskan batas negatif tertentu yang tidak dapat diungkapkan di Rust saat ini.

@bayu_joo

Pada saat yang sama izinkan saya memberikan saran terakhir saya: sebenarnya menurut saya kata kerja Detach yang disebutkan di atas juga cukup bagus, meskipun agak terlalu umum. Seperti yang saya katakan, saya bukan penutur asli, jadi saya tidak bisa berbicara untuk orang lain. Tolong anggap saja sebagai ide kecil.

Melepas tampaknya jauh lebih baik daripada nama seperti Pindah dan Relokasi, tetapi tampaknya bertentangan dengan kemungkinan penggunaan metafora pelepasan lainnya (mirip dengan bagaimana Escape dapat bertentangan dengan "analisis pelarian" dll). Hanya ada begitu banyak metafora yang kita miliki tentang bagaimana data dapat dikaitkan dengan data lain dalam ilmu komputer, yang membuat saya memikirkan keuntungan baru lain dari Lepas Pin: dengan berpisah erat pada metafora "pin", ia tidak menempati ruang untuk bahasa metafora di masa depan kita mungkin perlu menggunakan untuk tujuan yang berbeda, seperti nama-nama seperti Detach atau Escape atau Relocate bisa.

@withoutboats Saya tidak memiliki preferensi khusus untuk nama atau banyak investasi dalam bikeshed ini ... tapi saya penasaran; apa tujuan lain yang cocok Detach (jika Anda berspekulasi ...)?

@Centril Saya tidak memiliki kasus penggunaan yang jelas dalam pikiran, tetapi saya dapat membayangkan beberapa kasus penggunaan yang terkait dengan perusakan, misalnya.

@withoutboats Ya itu masuk akal; Bersulang!

@withoutboats Saya tidak yakin apakah entri Wiktionary adalah motivasi terbaik untuk membenarkan penamaan Unpin untuk mengaktifkan move from a pin . Metafora representasi fisik menderita karena fakta bahwa bergerak di Rust tidak menghilangkan objek di dunia. Untuk lebih tepatnya, 'upinning' pointer yang disematkan tidak memberi saya kendali atas memori yang dirujuk, alokasi dan validitasnya sebagai representasi objek T masih diperlukan dan dijamin oleh semantik pointer. Oleh karena itu, melepas pin tidak memberikan representasi terkontrol penuh dari T , seperti yang dilakukan unboxing. Dan, entri kamus yang mendefinisikan unpinning dalam istilah moving sebenarnya adalah bagian dari kebingungan lebih dari sekadar pembenaran nama seperti itu.

Dalam API yang diusulkan, tidak ada metode yang memiliki efek seperti itu (dan juga tidak dalam lingkup pin). Saya tidak melihat cara yang aman misalnya untuk melakukan transisi Pin<Box<T>> ke Box<T> (dan dengan ekstensi ke T ) dan saya juga tidak yakin apakah Unpin harus memiliki kemungkinan yang begitu kuat. Saya tidak yakin di mana semua perbedaannya. Tapi sejauh yang saya mengerti, Pin berlaku untuk beberapa lokasi memori sementara Unpin menjamin bahwa tidak ada dalam representasi T s bergantung pada jaminan pin. Namun, apakah itu sama dengan bisa mengeluarkan dan melupakan memori sepenuhnya? Saya pikir tidak. Saya akan memikirkan contoh yang lebih konkret.

Sunting: Lebih konkretnya, bahkan jika T adalah Unpin , dapatkah saya mengandalkan beberapa contoh T::drop(&mut) dipanggil pada memori yang disematkan, sebelum memori itu dibatalkan alokasinya? Sejauh yang saya tahu dari formalisme, jawabannya harus ya, tetapi nama Unpin mengkomunikasikan sebaliknya kepada saya.

Edit 2: Rc memungkinkan seseorang untuk mengamati Pin<&T> tetapi untuk T: Unpin masih belum memiliki drop dipanggil ke lokasi memori asli. Buat referensi tetap hidup di luar pin, kemudian setelah pin dijatuhkan Anda dapat keluar dengan Rc::try_unwrap . https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=dec6f6c6d2c0903d87a4a9cefe50a0ca Itu secara efektif menjawab pertanyaan melalui mekanisme yang ada, tetapi apakah berfungsi sebagaimana mestinya?

Mungkin IgnorePin ? Jika T adalah IgnorePin Anda dapat memperlakukan Pin<Box<T>> sebagai &mut T pada dasarnya mengabaikan keberadaan Pin (AIUI juga mengabaikan Box ). Untuk mengabaikan adalah kata kerja, saya kira IgnorePin bukan tapi saya tidak yakin apa itu. IgnorePin adalah deskriptif tentang apa yang diizinkan, ini tidak menjelaskan batasan yang ditempatkan pada tipe, tetapi juga tidak Unpin .

@wmanley Saya memiliki ide yang sangat mirip, ElidePin , dalam beberapa komentar di atas meskipun saat itu saya belum dapat mengungkapkan secara konkret mengapa yang satu itu terasa lebih tepat. Tapi saya setuju bahwa 'satu kata kerja' adalah panduan gaya untuk ciri penanda Rust. Meskipun ini juga memungkinkan negasi yang lebih alami dalam bentuk !ElidePin / !IgnorePin , ini tidak optimal.

@withoutboats Pertanyaan tindak lanjut: Karena pin tampaknya ditentukan dalam kaitannya dengan memori yang mendasarinya, bagaimana Pin berinteraksi dengan ZST? Karena Pinned menjadi ZST, bahkan ZST bisa jadi Unpin atau tidak. Saya akan secara intuitif mengatakan bahwa representasi memorinya tidak pernah secara resmi dibatalkan, jadi T::drop(&mut self) tidak perlu dipanggil, sangat mirip dengan bagaimana seseorang dapat membuat pin dari memori &mut 'static _ misalnya dari Box bocor

Apakah aman membuat Pin<P<T>> dengan T: !Unpin dan kemudian segera melepas pin nilainya, jika dijamin tidak ada yang memperhatikan pemasangan pin? Apakah ini hanya perilaku tidak terdefinisi jika nilai yang disematkan dipindahkan setelah metode mirip polling dipanggil?

@HeroicKatora Sayangnya, hari ini mungkin untuk mengimplementasikan Drop untuk tipe yang bisa menjadi !Unpin karena obat generik, misalnya:

struct S<T>(T); // `!Unpin` if `T: !Unpin`
impl<T> Drop for S<T> { ... }

@cramertj Terima kasih, baru saja menyadarinya.

@cramertj Jadi defaultnya ke T: ?Unpin pada batas umum? Apakah ada alasan lain di balik tidak default ke T: Unpin untuk tipe yang sudah ada seperti Sized ? Ini akan memberikan beberapa contoh di mana itu akan menjadi sangat ketat tetapi dapatkah tambahan otomatis itu menyebabkan regresi?

@HeroicKatora Itu akan membutuhkan taburan ?Unpin batas pada setiap jenis di perpustakaan standar dan dalam sekumpulan kode yang tidak peduli tentang Unpin sama sekali.

Ini juga aman untuk menambahkan bidang PhantomPinned, sebagai cara lain untuk membuat jenis Jatuhkan +! Lepas pin.

Apakah ada alasan lain di balik tidak default ke T: Lepas pin untuk tipe yang ada?

Lepas pin hanyalah sifat otomatis seperti Kirim dan Sinkronkan, proposal ini tidak melibatkan fitur bahasa baru. Jadi ia memiliki semantik yang sama dengan sifat otomatis yang sudah didefinisikan, yaitu bahwa sifat tersebut tidak diterapkan ke generik secara default (tidak seperti Sized, yang merupakan sifat bawaan untuk kompilator, bukan sifat otomatis).

Apakah ini hanya perilaku tidak terdefinisi jika nilai yang disematkan dipindahkan setelah metode mirip polling dipanggil?

Kami harus menjelaskan di sini bahwa perilaku tidak terdefinisi dalam konteks ini sebenarnya bukanlah jenis UB yang tradisional. Sebaliknya, kode itu, mengamati jenis dalam Pin, dapat membuat asumsi tentang semantik kepemilikan dari nilai itu (yaitu, jika tidak mengimplementasikan Lepas pin, itu tidak akan dipindahkan lagi atau tidak valid sampai destruktornya telah berjalan). Ini bukan UB dalam arti diasumsikan oleh kompilator tidak akan pernah terjadi (kompilator tidak tahu apa itu Pin).

Jadi ya, dalam artian Anda dapat memverifikasi bahwa tidak ada kode yang bergantung pada jaminan yang Anda berikan. Tetapi juga apa yang telah Anda lakukan tentu saja tidak ada gunanya, karena tidak ada kode yang dapat mengamati bahwa tipe itu disematkan.

@cramertj Begitu , itu akan sedikit disayangkan. Saya agak tidak nyaman dengan Pin interaksi dengan Drop dalam spesifikasi tetapi tidak dalam bahasa. Cukup bertentangan antara kebenaran antarmuka, kegunaan, dan merilisnya dalam waktu dekat. Bisakah saya mendapatkan klarifikasi tentang Sunting 2 di atas:

Rc memungkinkan seseorang untuk mengamati Pin <& T> tetapi untuk T: Unpin masih belum memanggil drop di lokasi memori asli. Biarkan referensi tetap hidup di luar pin, kemudian setelah pin dijatuhkan Anda dapat keluar dengan Rc :: try_unwrap. https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=dec6f6c6d2c0903d87a4a9cefe50a0ca

@HeroicKatora Masalah dengan kode Anda adalah Mem<'a>: Unpin , tetapi baris kode tidak aman yang Anda gunakan bergantung pada asumsi yang hanya berlaku untuk jenis yang tidak menerapkan Unpin . Saya telah mengedit inti Anda untuk menyertakan bukti bahwa Mem<'a>: Unpin : https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=201d1ae382f590be8c5cac13af279aff

Anda mengandalkan Lepas Pin terikat saat memanggil Pin::new , yang hanya dapat dipanggil pada penunjuk yang targetnya mengimplementasikan Lepas Pin.

Celah yang Anda pikir Anda temukan telah dipertimbangkan, itulah sebabnya tidak ada cara untuk mengubah dari Rc<T: ?Unpin> menjadi Pin<Rc<T>> . Anda harus membangun Rc di pin dengan Rc::pinned .

@withoutboats Hanya ingin mendapatkan konfirmasi itu, bahwa T: Unpin memang juga menyisih dari panggilan drop sebelum pembatalan. Itu menimbulkan pertanyaan, haruskah ada juga

fn into_inner(Pin<P>) -> P where P: Deref, P::Target: Unpin;

karena tidak melindungi bagian mana pun dari antarmuka, dan membuka bungkus Pin<Box<T>> menjadi Box<T> berpotensi berguna (tentu saja untuk T: Unpin ).

@HeroicKatora Anda benar bahwa fungsi itu akan aman. Saya tidak keberatan menambahkannya tetapi saya ingin menghindari perluasan API yang kami stabilkan saat ini , karena utas ini sudah berisi ratusan komentar. Kami selalu dapat menambahkannya nanti saat diperlukan seperti yang kami lakukan dengan semua API std.

Saya hanya akan mengatakan bahwa kedua penamaan dan fungsi dari Unpin membuat lebih banyak dirasakan akal dengan metode berkomunikasi. Dan mengetahui bahwa jaminan Pin memang terbatas pada T: !Unpin . Itu juga akan secara langsung ditunjukkan dengan adanya metode seperti itu, alih-alih membangun pintu keluar untuk menunjukkan kemungkinan: smile:. Dan dokumentasinya akan menjadi tempat yang tepat untuk menjelaskan (atau menautkan sekali lagi ke) pembatasan. (Seseorang bahkan mungkin mempertimbangkan untuk menamakannya unpin daripada into_inner ).

Sunting: Ini sebagian besar hanya akan menggeneralisasi apa yang sudah ada.

impl<P> Pin<P> where P: Deref, P::Target: Unpin

  • fn unpin(self) -> P

memiliki instantiation untuk P=&'a mut T , yang setara dengan yang diusulkan

impl<'a, T: ?Sized> Pin<&'a mut T> where T: Unpin

  • fn get_mut(self) -> &'a mut T

Sekarang setelah stabilisasi berjalan, inti dari PFCP tampaknya diperdebatkan, jadi oleh karena itu:

@rhmhhh batal

Apakah ada pelacakan untuk memastikan komentar yang dikembangkan mulai dari https://github.com/rust-lang/rust/issues/55766#issuecomment-437374982 diubah menjadi dokumen? Sepertinya kami sudah terlambat untuk rilis karena beta telah bercabang ... meskipun itu secara eksplisit dipanggil di sini untuk terjadi sebelum stabilisasi: /

Apakah ada alasan mengapa ini masih terbuka? @Centril Anda menutup dan membuka kembali ini, apakah itu disengaja?

@RalfJung Saya mencoba untuk membatalkan FCP tetapi tidak mendengarkan; @alexcrichton Bisakah Anda membatalkan FCP?

Ini stabil, jadi tutup.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat