Rust: [استقرار] دبوس APIs

تم إنشاؤها على ٧ نوفمبر ٢٠١٨  ·  213تعليقات  ·  مصدر: rust-lang/rust

تضمينrfcbot fcp
اسم الميزة: pin
هدف الاستقرار: 1.32.0
مشكلة التتبع: # 49150
طلبات التعليقات ذات الصلة: rust-lang / rfcs # 2349

هذا اقتراح لتحقيق الاستقرار في ميزة مكتبة pin ، مما يجعل "التثبيت"
واجهات برمجة التطبيقات (APIs) لمعالجة الذاكرة المثبتة التي يمكن استخدامها على المستقرة.

(لقد حاولت كتابة هذا الاقتراح باعتباره "تقرير استقرار" شامل.)

ميزة مستقرة أو واجهات برمجة التطبيقات

[std|core]::pin::Pin

يؤدي هذا إلى تثبيت النوع Pin في الوحدة الفرعية pin من std / core . Pin هو
غلاف أساسي وشفاف حول نوع عام P ، وهو المقصود
ليكون نوع المؤشر (على سبيل المثال ، Pin<&mut T> و Pin<Box<T>> كلاهما
صالح ، بنيات مقصودة). يعدل الغلاف Pin المؤشر إلى "دبوس"
الذاكرة التي تشير إليها في مكانها ، مما يمنع المستخدم من تحريك الأشياء للخارج
من تلك الذاكرة.

الطريقة المعتادة لاستخدام النوع Pin هي إنشاء متغير مثبت للبعض
نوع من امتلاك المؤشر ( Box ، Rc ، إلخ). مكتبة الأمراض المنقولة جنسيا التي تمتلك جميع المؤشرات
قدم مُنشئ pinned الذي يُرجع هذا. ثم ، للتلاعب في
القيمة الداخلية ، توفر كل هذه المؤشرات طريقة للتراجع نحو Pin<&T>
و Pin<&mut T> . يمكن للمؤشرات المثبتة أن تنفصل ، مما يعيدك &T ، لكن لا يمكن ذلك
deref بشكل آمن: هذا ممكن فقط باستخدام get_mut غير الآمن
وظيفة.

نتيجة لذلك ، سيُطلب من أي شخص يقوم بتحويل البيانات من خلال دبوس دعم ملف
ثابتًا أنهم لا يخرجون أبدًا من تلك البيانات. هذا يسمح لكود آخر
افترض بأمان أن البيانات لا يتم نقلها أبدًا ، مما يسمح لها باحتواء (لـ
مثال) المراجع الذاتية.

سيحتوي النوع Pin على واجهات برمجة التطبيقات المستقرة التالية:

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

تشير السمة

معظم السمات التي تشير إلى Pin هي عن ظهر قلب إلى حد ما ، فهذان العنصران مهمان
عملها:

  • 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

Unpin هي سمة تلقائية آمنة تتجاهل ضمانات التثبيت. إذا كان
هدف المؤشر المثبت ينفذ Unpin ، فهو آمن بشكل قابل للتغيير
إشارة إليه. Unpin ليس لديهم أي ضمانات بأنهم لن يفعلوا ذلك
من Pin .

هذا يجعل من المريح التعامل مع إشارة مثبتة لشيء ما
لا يحتوي على مراجع ذاتية لأنه سيكون من التعامل مع غير مثبت
مرجع. ضمانات Pin مهمة فقط لأنواع الحالات الخاصة مثل
الهياكل المرجعية الذاتية: هذه الأنواع لا تقوم بتطبيق Unpin ، لذلك قاموا بتطبيقها
قيود النوع Pin .

عمليات التنفيذ البارزة لـ Unpin في الأمراض المنقولة جنسياً:

  • 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>

هذه تقنن فكرة أن التثبيت ليس متعدٍ عبر المؤشرات. ذلك
هو ، Pin<&T> فقط بتثبيت كتلة الذاكرة الفعلية الممثلة بـ T في أ
مكان. لقد تم الخلط بين المستخدمين في بعض الأحيان بسبب هذا وتوقعوا هذا النوع
مثل Pin<&mut Box<T>> يثبّت بيانات T في مكانه ، لكنه يقوم فقط بتثبيت
الذاكرة يشير المرجع المثبت بالفعل إلى: في هذه الحالة ، Box 's
التمثيل ، وهو مؤشر في الكومة.

std::marker::Pinned

النوع Pinned هو نوع ZST الذي لا يطبق Unpin ؛ يسمح لك
قم بإلغاء التنفيذ التلقائي لـ Unpin على المستقر ، حيث يتم تضمين !Unpin
لن تكون مستقرة بعد.

صانعي المؤشر الذكي

تتم إضافة المُنشئين إلى المؤشرات الذكية للأمراض المنقولة جنسياً لإنشاء مراجع مثبتة:

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

ملاحظات حول التثبيت والسلامة

على مدار الأشهر التسعة الماضية ، مرت واجهات برمجة التطبيقات المثبتة بالعديد من التكرارات مثل
لقد حققنا في قوتهم التعبيرية وكذلك صحة
ضمانات. أود الآن أن أقول بثقة أن واجهات برمجة التطبيقات المثبتة استقرت هنا
سليمة وقريبة بدرجة كافية من الحد الأقصى المحلي في بيئة العمل و
التعبير. هذا جاهز للاستقرار.

تتمثل إحدى المشكلات الأكثر تعقيدًا في التثبيت في تحديد متى يكون الأداء آمنًا
إسقاط دبوس : أي الانتقال من Pin<P<Target = Foo>> إلى a
Pin<P<Target = Bar>> ، حيث Bar هو حقل Foo . لحسن الحظ ، لدينا
تمكنت من تقنين مجموعة من القواعد التي يمكن أن تساعد المستخدمين على تحديد ما إذا كان هذا
العرض آمن:

  1. من الآمن تثبيت المشروع فقط إذا كان (Foo: Unpin) implies (Bar: Unpin) : هذا
    هو ، إذا لم تكن الحالة أن Foo (النوع المحتوي) هو Unpin بينما
    Bar (النوع المتوقع) ليس Unpin .
  2. يكون آمنًا فقط إذا لم يتم نقل Bar أبدًا أثناء تدمير Foo ،
    بمعنى أنه إما أن Foo ليس به مدمر ، أو أن المدمر هو بعناية
    تم التحقق منه للتأكد من أنه لا يتحرك أبدًا خارج المجال الذي يتم عرضه عليه.
  3. يكون آمنًا فقط إذا كان Foo (النوع المحتوي) ليس repr(packed) ،
    لأن هذا يتسبب في نقل الحقول لإعادة تنظيمها.

بالإضافة إلى ذلك ، لا توفر واجهات برمجة تطبيقات الأمراض المنقولة جنسياً طريقة آمنة لتثبيت الكائنات في المكدس.
هذا لأنه لا توجد طريقة لتنفيذ ذلك بأمان باستخدام وظيفة API.
ومع ذلك ، يمكن للمستخدمين تثبيت الأشياء بشكل غير آمن في المكدس من خلال ضمان ذلك
لا تحرك الكائن مرة أخرى بعد إنشاء المرجع المثبت.

يحتوي الصندوق pin-utils على crates.io على وحدات ماكرو للمساعدة في كل من المكدس
التثبيت ودبوس الإسقاط. يقوم المكدس الذي يقوم بتثبيت الماكرو بتثبيت الكائنات بأمان في ملف
مكدس باستخدام خدعة تتضمن التظليل ، بينما يوجد ماكرو للإسقاط
وهو أمر غير آمن ، ولكنه يتجنب الاضطرار إلى كتابة نموذج الإسقاط
والتي يمكن أن تقدم رمزًا غير آمن آخر غير صحيح.

تغييرات التنفيذ قبل التثبيت

  • [] قم بتصدير Unpin من المقدمة ، وإزالة إعادة التصدير pin::Unpin

كقاعدة عامة ، نحن لا نعيد تصدير الأشياء من أماكن متعددة في الأمراض المنقولة جنسياً إلا إذا
واحد هو وحدة فائقة من التعريف الحقيقي (على سبيل المثال تقصير
std::collections::hash_map::HashMap إلى std::collections::HashMap ). لهذا
السبب ، إعادة تصدير std::marker::Unpin من std::pin::Unpin خارج
مكان.

في الوقت نفسه ، يتم تضمين سمات علامة مهمة أخرى مثل الإرسال والمزامنة
في المقدمة. لذا فبدلاً من إعادة تصدير Unpin من الوحدة النمطية pin ، بواسطة
وضعنا في المقدمة نجعل استيراد std::marker::Unpin غير ضروري ،
نفس سبب وضعه في pin .

  • [] تغيير الوظائف المرتبطة بأساليب

حاليًا ، لا تستخدم الكثير من الوظائف المرتبطة بـ Pin بنية الأسلوب.
من الناحية النظرية ، هذا لتجنب التعارض مع الأساليب الداخلية القابلة للاشتقاق. ومع ذلك،
لم يتم تطبيق هذه القاعدة باستمرار ، وفي تجربتنا تم ذلك في الغالب
جعل الأمور أكثر إزعاجًا. تقوم المؤشرات المثبتة بتطبيق ثابت فقط
deref ، غير مشتق قابل للتغيير أو اشتقاق بالقيمة ، يحد من القدرة على الاشتقاق
على أي حال. علاوة على ذلك ، فإن العديد من هذه الأسماء فريدة إلى حد ما (مثل map_unchecked )
ومن غير المرجح أن تتعارض.

بدلاً من ذلك ، نفضل إعطاء الطرق Pin الأسبقية المستحقة ؛ المستخدمين الذين
تحتاج إلى الوصول إلى طريقة داخلية يمكن دائمًا استخدام UFCS ، تمامًا كما لو كانت
مطلوب للوصول إلى طرق Pin إذا لم نستخدم بنية الأسلوب.

  • [] أعد تسمية get_mut_unchecked إلى get_unchecked_mut

الترتيب الحالي غير متوافق مع الاستخدامات الأخرى في المكتبة القياسية.

  • [] إزالة impl<P> Unpin for Pin<P>

لا يتم تبرير هذا الضمني من خلال تبريرنا القياسي لتضمينات إلغاء التثبيت: لا يوجد اتجاه مؤشر بين Pin<P> و P . يتم تغطية فائدتها بواسطة الضمانات للمؤشرات نفسها.

ستحتاج هذه العقود الآجلة إلى التغيير لإضافة P: Unpin ملزم.

  • [] ضع علامة على Pin كـ repr(transparent)

يجب أن يكون الدبوس غلافًا شفافًا حول المؤشر بداخله ، بنفس التمثيل.

ميزات متصلة ومعالم أكبر

تعد واجهات برمجة التطبيقات الدبوسية مهمة لمعالجة أقسام الذاكرة بأمان والتي يمكن
أن تضمن عدم نقلها. إذا كانت الكائنات في تلك الذاكرة لا تفعل ذلك
تنفيذ Unpin ، لن يتغير عنوانهم أبدًا. هذا ضروري ل
إنشاء مولدات مرجعية ذاتية ووظائف غير متزامنة. كنتيجة ل،
و Pin يبدو نوع في المكتبة القياسية future اجهات برمجة التطبيقات وقريبا
تظهر في واجهات برمجة التطبيقات للمولدات أيضًا (# 55704).

يعد تثبيت النوع Pin وواجهات برمجة التطبيقات الخاصة به مقدمة ضرورية لتحقيق الاستقرار
واجهات برمجة التطبيقات Future ، والتي تعد بحد ذاتها مقدمة ضرورية لتحقيق الاستقرار في
بناء الجملة async/await ونقل النظام البيئي IO غير المتزامن بالكامل futures 0.3
على الصدأ المستقر.

تضمين التغريدة ccramertjRalfJung

T-libs finished-final-comment-period

التعليق الأكثر فائدة

هل هناك شخص ما في مأزق لكتابة فصل nomicon عن العقود الآجلة؟ يبدو ضروريًا بشكل لا يصدق بالنظر إلى مدى دقة ذلك. على وجه الخصوص ، أعتقد أن الأمثلة ، خاصة أمثلة على تطبيقات عربات التي تجرها الدواب / سيئة وكيف أنها غير سليمة ، ستكون مضيئة.

ال 213 كومينتر

تضمينrfcbot fcp

اقترح عضو الفريق withoutboats دمج هذا. الخطوة التالية هي المراجعة بواسطة باقي أعضاء الفريق المميزين:

  • [x] Kimundi
  • []SimonSapin
  • [x]alexcrichton
  • [x] dtolnay
  • []sfackler
  • [x] @ بدون قوارب

اهتمامات:

  • box-pinnned-vs-box-pin (https://github.com/rust-lang/rust/issues/55766#issuecomment-443371976)
  • تحسين الوثائق (https://github.com/rust-lang/rust/issues/55766#issuecomment-443367737)
  • تم حل تسمية Unpin عن طريق https://github.com/rust-lang/rust/issues/55766#issuecomment -445074980
  • الأساليب الذاتية (https://github.com/rust-lang/rust/issues/55766#issuecomment-443368794)

بمجرد موافقة أغلبية المراجعين (وتكون موافقتان على الأكثر معلقة) ، سيدخل هذا فترة التعليق النهائية. إذا اكتشفت مشكلة كبيرة لم تُثار في أي وقت في هذه العملية ، فيرجى التحدث!

راجع هذا المستند للحصول على معلومات حول الأوامر التي يمكن أن يقدمها لي أعضاء الفريق.

شكرا على الكتابة التفصيلية هناwithoutboats! لقد كنت مرتبكًا تاريخيًا نوعًا ما بسبب الضمانات المختلفة Pin ، ولدي حاليًا بعض الأسئلة حول واجهات برمجة التطبيقات (API) التي يتم تثبيتها هنا بموجب ضمانات السلامة. للمساعدة في حل هذا الأمر في رأسي ، على الرغم من أنني أدركت أنني سأحاول تدوين هذه الأشياء.

في محاولة لبدء تدوين هذا على الرغم من أنني استمر في الوقوف مقابل جدار من "ما هو Unpin ؟" أنا في حيرة من أمري بسبب ماهية ذلك والضمانات المختلفة المحيطة به. هل يمكنك أن تقول مرة أخرى ما يعنيه لـ T وكذلك عدم تنفيذ Unpin ؟ أيضًا ، إذا كان Unpin سمة آمنة لتنفيذها يبدو بسذاجة أنه يمكن استخدامها بسهولة لتقويض الضمانات غير الآمنة Pin<T> ، لكنني بالتأكيد أفتقد شيئًا

إذا كان هذا صحيحًا ، فإن كل نوع ليس مرجعيًا ذاتيًا (أي: ليس منشئًا) هو Unpin

إنها ليست مجرد مرجعية ذاتية ، فهناك بعض حالات الاستخدام الأخرى لعناوين الذاكرة المستقرة التي يمكن أن يدعمها أيضًا Pin . فهي قليلة نسبيًا ومتباعدة.

كيف أفهم أن يكون Unpin آمنًا للتنفيذ هو أنه من خلال تنفيذه ، قد تنتهك عنصرًا ثابتًا مطلوبًا لرمز آخر غير آمن كتبته (بشكل حاسم ، يمكنك فقط كتابة هذا الرمز غير الآمن ، ولا يمكن الاعتماد على أي رمز خارجي فيما إذا كان لقد قمت بتنفيذ Unpin ). لا يمكنك فعل أي شيء باستخدام واجهة برمجة التطبيقات الآمنة لـ Pin والتي ستسبب عدم الأمان سواء قمت بتنفيذ Unpin . باشتراكك في استخدام بعض من واجهة برمجة التطبيقات غير الآمنة الخاصة بـ Pin ، فإنك تضمن أنك ستنفذ Unpin عندما يكون ذلك آمنًا. هذا مشمول بالنقطة 1 من قسم "ملاحظات حول التثبيت والسلامة" أعلاه.

حسنًا ، ما زلت لا أفهم حقًا Unpin . أنا في البداية أحاول فقط فهم ما يعنيه التنفيذ أو عدم دفع Unpin .

أولاً ، ربما يكون من المفيد معرفة الأنواع التي تنفذ Unpin تلقائيًا! تم ذكره أعلاه أن أنواع المؤشرات الشائعة (Arc / Rc / Box / المراجع) تطبق Unpin ، لكنني أعتقد أن هذا كل شيء؟ إذا كانت هذه سمة تلقائية ، فهل يعني ذلك أن النوع MyType ينفذ تلقائيًا Unpin إذا كان يحتوي على مؤشرات فقط؟ أم لا توجد أنواع أخرى تقوم تلقائيًا بتنفيذ Unpin ؟

ما زلت أحاول تلخيص أو تحديد ما هي ضمانات Unpin وما شابه ذلك ، لكنني أجد صعوبة في القيام بذلك. هل يمكن لشخص المساعدة من خلال تكرار ما يعنيه تطبيق Unpin بالإضافة إلى ما يعنيه عدم تنفيذ Unpin ؟

أعتقد أنني أفهم ضمانات Pin<P> حيث لا يمكنك الخروج من أي من الأعضاء المضمنين من P::Target ، لكن هل هذا صحيح؟

alexcrichton شكرًا على الأسئلة ، أنا متأكد من أن تثبيت واجهات برمجة التطبيقات يمكن أن يكون مربكًا بعض الشيء للأشخاص الذين لم يكونوا جزءًا من المجموعة التي تركز عليها.

أولاً ، ربما يكون من المفيد معرفة الأنواع التي تنفذ إلغاء التثبيت تلقائيًا!

Unpin هي سمة تلقائية مثل Send أو Sync ، لذا تقوم معظم الأنواع بتطبيقها تلقائيًا. المولدات وأنواع الوظائف غير المتزامنة هي !Unpin . الأنواع التي يمكن أن تحتوي على منشئ أو جسم دالة غير متزامن (بمعنى آخر ، الأنواع ذات معلمات النوع) لا تكون أيضًا تلقائيًا Unpin ما لم تكن معلمات النوع الخاصة بها.

الضمانات الصريحة لأنواع المؤشر هي جعل Unpin حتى لو لم تكن معلمات النوع الخاصة بهم. ونأمل أن يكون سبب ذلك أوضح بنهاية هذا التعليق.

هل يمكن لأي شخص المساعدة من خلال التأكيد مرة أخرى على ما يعنيه تنفيذ Unpin وكذلك ما يعنيه عدم تنفيذ Unpin؟

هنا هو نوع الفكرة الأساسية لواجهات برمجة التطبيقات المثبتة. أولاً ، بالنظر إلى نوع المؤشر P ، Pin<P> يتصرف مثل P باستثناء أنه ما لم يكن P::Target ينفذ Unpin ، فإنه من غير الآمن أن يتم الرجوع بشكل متبادل Pin<P> . ثانيًا ، هناك نوعان من الثوابت الأساسية للرمز غير الآمن المتعلق بـ Pin يجب الحفاظ عليه:

  • إذا حصلت بشكل غير آمن على &mut P::Target من Pin<P> ، فلا يجب عليك أبدًا نقل P::Target .
  • إذا كان بإمكانك إنشاء Pin<P> ، فيجب التأكد من أنك لن تتمكن أبدًا من الحصول على مؤشر غير مثبت للبيانات التي يشير إليها المؤشر حتى يتم تشغيل أداة التدمير.

المعنى الضمني لكل هذا هو أنه إذا قمت ببناء Pin<P> ، فلن تتحرك القيمة المشار إليها بـ P مرة أخرى ، وهو الضمان الذي نحتاجه للهياكل المرجعية الذاتية بالإضافة إلى التدخلية المجموعات. ولكن يمكنك إلغاء الاشتراك في هذا الضمان بمجرد تنفيذ Unpin لنوعك.

لذلك إذا قمت بتطبيق Unpin لنوع ما ، فأنت تقول أن النوع يخترق أي ضمانات أمان إضافية Pin - من الممكن أن يتم الرجوع بشكل متبادل إلى المؤشرات التي تشير إليه. هذا يعني أنك تقول إن النوع لا يحتاج إلى أن يكون ثابتًا لاستخدامه بأمان.

نقل نوع المؤشر مثل Rc<T> لا يتحرك T لأن T خلف المؤشر. وبالمثل ، فإن تثبيت المؤشر على Rc<T> (كما في Pin<Box<Rc<T>> ) لا يؤدي في الواقع إلى تثبيت T ، بل يقوم فقط بتثبيت هذا المؤشر المحدد. هذا هو السبب في أن أي شيء يحافظ على الأدوية الخاصة به خلف مؤشر يمكنه تنفيذ Unpin حتى عندما لا تستخدم الأدوية الخاصة بهم.

أيضًا ، إذا كانت Unpin سمة آمنة لتنفيذها ، فيبدو بسذاجة أنها يمكن استخدامها لتقويض الضمانات غير الآمنة لـ Pin بسهولة، لكنني بالتأكيد أفتقد شيئًا ما

كان هذا أحد أصعب أجزاء واجهة برمجة تطبيقات التثبيت ، وقد أخطأنا في البداية.

Unpin تعني "حتى بعد وضع شيء ما في دبوس ، فمن الآمن الحصول على إشارة قابلة للتغيير إليه." هناك سمة أخرى موجودة اليوم تمنحك نفس الوصول: Drop . ما توصلنا إليه هو أنه نظرًا لأن Drop آمن ، يجب أن يكون Unpin آمنًا أيضًا. هل هذا يقوض النظام بأكمله؟ ليس تماما.

لتنفيذ نوع مرجعي ذاتي فعليًا سيتطلب كودًا غير آمن - من الناحية العملية ، الأنواع الوحيدة المرجعية الذاتية التي يهتم بها أي شخص هي تلك التي ينشئها المترجم لك: المولدات وآلات حالة الوظيفة غير المتزامنة. يقول هؤلاء صراحة أنهم لا يطبقون Unpin وليس لديهم تطبيق Drop ، لذلك تعلم ، لهذه الأنواع ، بمجرد أن يكون لديك Pin<&mut T> ، سوف لا تحصل في الواقع على مرجع قابل للتغيير ، لأنهم من النوع المجهول الذي نعرف أنه لا يطبق Unpin أو Drop.

تظهر المشكلة بمجرد أن يكون لديك بنية تحتوي على أحد هذه الأنواع المجهولة ، مثل المُدمج المستقبلي. من أجل الانتقال من Pin<&mut Fuse<Fut>> إلى Pin<&mut Fut> ، يجب عليك تنفيذ "إسقاط دبوس". هذا هو المكان الذي يمكن أن تواجه فيه مشكلة: إذا قمت بتثبيت المشروع في الحقل المستقبلي للمجمع ، ولكن بعد ذلك قمت بتطبيق Drop للمجمع ، يمكنك الخروج من الحقل الذي من المفترض أن يتم تثبيته.

لهذا السبب ، فإن إسقاط الدبوس غير آمن! من أجل أداء إسقاط دبوس دون انتهاك ثوابت التثبيت ، عليك أن تضمن عدم القيام بالعديد من الأشياء ، والتي أدرجتها في مقترح التثبيت.

لذا ، فإن tl ؛ dr: Drop موجود ، لذا يجب أن يكون Unpin آمنًا لكن هذا لا يفسد الأمر برمته ، فهذا يعني فقط أن إسقاط الدبوس هو unsafe وأي شخص يريد تثبيت المشروع يحتاج إلى دعم مجموعة من الثوابت.

المولدات وآلات حالة الوظائف غير المتزامنة. يقول هؤلاء صراحة أنهم لا يطبقون Unpin وليس لديهم تطبيق Drop ، لذلك تعلم ، بالنسبة لهذه الأنواع ، بمجرد أن يكون لديك رقم تعريف شخصي <& mut T> ، فلن يحصلوا في الواقع على مرجع متغير ، لأنهم نوع مجهول نعرفه لا يطبق Unpin أو Drop.

ألا يجب أن يكون لجهاز الحالة غير المتزامن تنفيذ Drop ؟ يجب تدمير الأشياء الموجودة على "مكدس" الدالة غير المتزامنة (والتي ربما تساوي الحقول في آلة الحالة) عندما تكتمل الدالة غير المتزامنة أو تُلغى. أم أن هذا يحدث بطريقة أخرى؟

أعتقد أن ما يهم في هذا السياق هو ما إذا كان العنصر impl Drop for Foo {…} موجودًا ، والذي من شأنه تشغيل رمز مع &mut Foo والذي يمكن أن يستخدم على سبيل المثال mem::replace لـ "exfiltrate" ونقل Foo قيمة.

هذا ليس هو نفسه "قطرة الغراء" ، والتي يمكن استدعاؤها من خلال ptr::drop_in_place . إسقاط الغراء لنوع معين من النوع Foo سوف يستدعي Drop::drop إذا تم تنفيذه ، ثم استدعاء متكرر للغراء المتكرر لكل حقل. لكن هذه الاستدعاءات المتكررة لا تتضمن أبدًا &mut Foo .

أيضًا ، بينما يحتوي المولد (وبالتالي آلة الحالة غير المتزامنة) على غراء مخصص للإسقاط ، إلا أنه يقوم فقط بإسقاط مجموعة الحقول الصحيحة بناءً على الحالة الحالية ، إلا أنه يعد بعدم تحريك أي من الحقول مطلقًا أثناء الإفلات.

المصطلح الذي أستخدمه (على الرغم من أنني لا أعتقد أن هناك أي معيار): "إسقاط الغراء" هو المترجم الذي تم إنشاؤه بشكل متكرر للحقول ، واستدعاء المدمرات ؛ "إفلات التطبيق" هو ​​تنفيذ للسمة Drop ، و "التدمير" هو مزيج من غراء الإسقاط وتطبيق Drop. لا يتحرك الغراء المسقط أبدًا في أي شيء ، لذلك نحن نهتم فقط بتطبيقات Drop.

هل هناك شخص ما في مأزق لكتابة فصل nomicon عن العقود الآجلة؟ يبدو ضروريًا بشكل لا يصدق بالنظر إلى مدى دقة ذلك. على وجه الخصوص ، أعتقد أن الأمثلة ، خاصة أمثلة على تطبيقات عربات التي تجرها الدواب / سيئة وكيف أنها غير سليمة ، ستكون مضيئة.

@ Gankro بالتأكيد ، يمكنك أن

شكرا على الشرح جميعا!

أنا شخصياً أنا جديد تمامًا على Async Rust و Pin APIs ، لكنني لعبت معها قليلاً خلال الأيام الأخيرة (https://github.com/rust-lang-nursery/futures-rs/pull/1315 - حيث حاولت استغلال التثبيت للمجموعات المتطفلة في رمز غير متزامن).

أثناء التجريب لدي بعض المخاوف بشأن واجهات برمجة التطبيقات هذه:

  • يبدو من الصعب جدًا فهم مفهوم التثبيت تمامًا ، حتى لو كان المرء يعرف أن عناوين الذاكرة الثابتة مطلوبة. بعض التحديات التي واجهتها:

    • رسائل خطأ مثل:

      > داخل impl core::future::future::Future+futures_core::future::FusedFuture ، لم يتم تنفيذ السمة std::marker::Unpin لـ std::marker::Pinned

      هذا يبدو متكررًا جدًا ومتناقضًا (لماذا لا يتم تثبيت شيء مثبت؟)

    • كيف يمكنني الوصول إلى الحقول القابلة للتغيير في أسلوبي التي تأخذ رقم التعريف الشخصي كمعامل. استغرق الأمر بعض البحث ، والتعرف على المصطلحات الجديدة (إسقاط Pin ) ، ومحاولة نسخ الأساليب من pin-utils ، حتى توصلت إلى حل يستخدم طريقتين غير آمنين للقيام بما أحتاجه .

    • كيف يمكنني بالفعل استخدام مستقبلي في طريقة async وحالة select . اتضح أنني بحاجة إلى pin_mut!() لمكدس العقود الآجلة. وهو ليس مكدسًا حقًا ، مما يجعله محيرًا.

    • لماذا تستخدم طريقة drop() الآن مرة أخرى &mut self ، بدلاً من Pin .

    • بشكل عام ، كان هناك شعور بالاستخدام العشوائي لواجهات برمجة التطبيقات غير الآمنة ذات الصلة بالتثبيت على أمل تجميع الأشياء ، وهو بالتأكيد لا ينبغي أن يكون الوضع المثالي. أظن أن الآخرين قد يحاولون فعل أشياء مماثلة.

  • ينتشر هذا المفهوم كثيرًا في جميع أنحاء قاعدة البيانات ، والذي يبدو أنه يجبر الكثير من الناس على فهم معنى Pin و Unpin الواقع. يبدو هذا وكأنه تسريب بعض الشيء لتفاصيل التنفيذ لبعض حالات الاستخدام الخاصة.
  • يبدو أن Pin مرتبطًا إلى حد ما بأعمار ، ولكنه أيضًا متعامد إلى حد ما. يخبرنا Pin بشكل أساسي أننا قد نرى كائنًا مرة أخرى بنفس العنوان تمامًا حتى يتم استدعاء drop() . مما يمنحه نوعًا من العمر الافتراضي بين النطاق الحالي و 'static . يبدو محيرًا أن يكون لديك مفهومان مرتبطان ، لكنهما لا يزالان مختلفين تمامًا. تساءلت عما إذا كان يمكن تصميمه بشيء مثل 'pinned .

أثناء تجميع الأشياء ، فكرت غالبًا في C ++ ، حيث يتم تجنب معظم هذه المشكلات: يمكن الإعلان عن الأنواع غير المنقولة عن طريق حذف مُنشئ النقل وعامل التعيين. عندما يكون نوع ما غير قابل للنقل ، فإن الأنواع التي تحتوي على هذا النوع ليست كذلك. وبالتالي ، تتدفق الخاصية والمتطلبات بشكل أصلي من خلال التسلسل الهرمي للنوع ويتم فحصها بواسطة المترجم ، بدلاً من إعادة توجيه الخاصية داخل بعض المكالمات (وليس جميعها ، على سبيل المثال ليس drop() ). أعتقد أن هذا أسهل بكثير للفهم. ولكن ربما لا ينطبق على Rust ، نظرًا لأنه يجب نقل Future s حاليًا قبل أن يبدأ شيء ما في الاقتراع عليهم؟ ولكن من ناحية أخرى ، قد يكون ذلك قابلاً للإصلاح بتعريف جديد بهذه السمة ، أو فصل الحركة عن مرحلة الاقتراع.

بخصوص تعليق Alex Unpin : أنا أفهم ببطء ما تعنيه Unpin ، لكنني أوافق على أنه من الصعب فهمه. ربما يساعد اسم آخر ، لكن لا يمكنني العثور على اسم موجز في الوقت الحالي. شيء ما على طول ThingsInsideDontBreakIfObjectGetsMoved ، DoesntRequireStableAddress ، PinDoesntMatter ، إلخ.

ما لم أفهمه تمامًا بعد هو ، لماذا لا يمكن أن يكون الحصول على &mut self من Pin<&mut self> آمنًا لجميع الأنواع. إذا كان Pin يعني أن عنوان الكائن نفسه مستقر ، فيجب أن يكون هذا صحيحًا بالنسبة لمعظم أنواع الصدأ النموذجية. يبدو أن هناك مصدر قلق آخر مدمج في Pin ، وهو أن الأنواع المرجعية الذاتية داخله لا تنكسر. بالنسبة لتلك الأنواع ، فإن التلاعب بها بعد الحصول على Pin غير آمن دائمًا. لكنني أعتقد أنه في معظم الحالات سيتم إنشاء هذه الأشياء من خلال مترجم ، ويجب أن يكون عدم الأمان أو حتى المؤشرات الأولية جيدًا. بالنسبة إلى أدوات الدمج المستقبلية يدويًا التي تحتاج إلى إعادة توجيه المكالمات المثبتة إلى الحقول الفرعية ، من الواضح أنه يلزم أن تكون مكالمات غير آمنة لإنشاء دبابيس للحقول قبل الاقتراع عليها. ولكن في هذه الحالة ، أرى أن عدم الأمان يرتبط بالمكان الذي يهم حقًا (هل لا يزال الدبوس صالحًا؟) أكثر من الوصول إلى الحقول الأخرى التي لا يهمها على الإطلاق.

فكرة أخرى راودتني هي ما إذا كان من الممكن الحصول على نظام أبسط إذا تم تطبيق بعض القيود. على سبيل المثال ، إذا كان من الممكن استخدام الأشياء التي تتطلب التثبيت فقط داخل طرق غير متزامنة وليس مع أدوات دمج مستقبلية. ربما يمكن أن يبسط ذلك الأشياء إلى Pin أو Unpin . بالنظر إلى أنه بالنسبة للكثير من طرق عدم التزامن / انتظار الكود مع دعم التحديد / الانضمام قد تكون مواتية للمُدمج ، فقد لا تكون هذه أكبر خسارة. لكنني لم أفكر حقًا فيما إذا كان هذا يساعد حقًا.

على الجانب الإيجابي: أن تكون قادرًا على كتابة كود غير متزامن / انتظار باستخدام أقترض "المكدس" أمر رائع ومطلوب بشدة! والقدرة على استخدام التثبيت لحالات الاستخدام الأخرى ، مثل المجموعات المتطفلة ، ستساعد في الأداء وكذلك الأهداف مثل الأنظمة أو النواة المدمجة. لذلك أنا أتطلع حقًا إلى حل في هذا الشأن.

الصمت الصغرى في تقرير التثبيت:

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

أظن أن هذا في الواقع unsafe fn ؟

@ Matthias247 لا يمكنك الحصول على & mut T بأمان من Pin<P<T>> إذا لم يكن T Unpin لأنه يمكنك بعد ذلك mem::swap لإخراج T من Pin ، الأمر الذي من شأنه أن يهزم الغرض من تثبيت الأشياء.

هناك شيء واحد أجد صعوبة في شرحه لنفسي وهو ما يجعل Future يختلف اختلافًا جوهريًا عن السمات الأخرى مثل أن Pin يحتاج إلى أن يكون جزءًا من API الخاص به. أعني ، أنا أعلم حدسيًا أن السبب في ذلك هو أن عدم التزامن / الانتظار يتطلب التثبيت ، لكن هل هذا يقول شيئًا محددًا عن العقود الآجلة يختلف عن التكرار ، على سبيل المثال؟

هل يمكن أن يأخذ الاستطلاع ويغير نفسه وينفذ فقط أنواع المستقبل Pin<P> أو الأنواع التي يتم إلغاء تثبيتها؟

كيف يمكنني الوصول إلى الحقول القابلة للتغيير في أسلوبي التي تأخذ رقم التعريف الشخصي كمعامل.

هذا يجعلني في الواقع أتساءل عما إذا كانت هناك طريقتان مفقودتان في 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>
}

يمكن استخدامها في الماكرو pin_utils::unsafe_unpinned! .

أحاول استنتاج _لماذا_ يدعي هذا الماكرو أنه غير آمن. إذا كان لدينا !Unpin ولدينا حقل Unpin ، فلماذا يكون المشروع في هذا الحقل غير آمن؟

الموقف الوحيد الذي يمكنني أن أرى فيه أنه غير سليم هو تنفيذ نوع مخصص !Unpin ، مع أخذ مؤشر خام إلى حقل ذاتي Unpin (والاعتماد على وجود عنوان ثابت / يشير إلى نفس المثال) ، ثم الحصول على &mut لنفس الحقل وتمريره إلى وظيفة خارجية. يبدو أن هذا يندرج تحت نفس المنطق الذي يجعل تنفيذ Unpin آمنًا ، من خلال أخذ مؤشر خام إلى حقل !Unpin فأنت تختار عدم القدرة على استدعاء بعض الخزائن واجهات برمجة التطبيقات.

لجعل الوضع السابق أكثر أمانًا ، يمكن أن يكون هناك غلاف مبني على Pinned لوضع العلامات والذي عادةً ما يكون Unpin حقول الهيكل في الواقع !Unpin بدلاً من إضافة Pinned للبنية ككل:

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 { ... }
}

يبدو كل هذا متوافقًا مع واجهة برمجة التطبيقات الحالية ، فقد يزيل بعض عدم الأمان من أدوات التجميع futures-rs (على سبيل المثال ، ستوفر وصولاً آمنًا إلى حقول إضافية مثل هذا الحقل) ، ولكنها ليست ضرورية لحالات الاستخدام الحالية. ربما يمكننا تجربة بعض واجهات برمجة التطبيقات مثل هذا لتنفيذ أنواع مخصصة !Unpin (مثل المجموعات المتطفلة) وإضافتها لاحقًا.

@ Nemo157 وظائف الخريطة هذه غير آمنة لأنه يمكنني mem::swap على &mut T تقوم الوظيفة بتمريرني قبل إرجاع &mut U . (حسنًا ، الشيء القابل للتغيير هو ، قد لا يكون غير القابل للتغيير غير آمن)

تحرير: يختلف ماكرو pin-utils أيضًا ، فلا علاقة لـ unsafe_unpinned بنوع الهدف الذي يكون Unpin ، إنه مجرد "إسقاط غير مثبت" - إسقاط إلى &mut Field . إنه آمن للاستخدام طالما لم تقم أبدًا بتثبيت المشروع في هذا الحقل ، حتى لو كان الحقل !Unpin .

هناك شيء واحد أجد صعوبة في شرحه لنفسي وهو ما يجعل Future يختلف اختلافًا جوهريًا عن السمات الأخرى مثل أن Pin يحتاج إلى أن يكون جزءًا من API الخاص به. أعني ، أنا أعلم حدسيًا أن السبب في ذلك هو أن عدم التزامن / الانتظار يتطلب التثبيت ، لكن هل هذا يقول شيئًا محددًا عن العقود الآجلة يختلف عن التكرار ، على سبيل المثال؟

لا يوجد فرق نظري ، لكن هناك اختلافات براغماتية. لأحد ، Iterator ثابت. ولكن نتيجة لذلك ، ما لم نكتشف شيئًا ذكيًا جدًا ، فلن تتمكن أبدًا من تشغيل حلقة for عبر مولد مرجعي ذاتي بدون مراوغة مزدوجة ، على الرغم من أن ذلك يجب أن يكون آمنًا تمامًا بدونه ( لأن الحلقة for ستستهلك ولن تحرك المولد أبدًا).

الاختلاف العملي المهم الآخر هو أن أنماط الكود بين Iterator و Future مختلفة تمامًا. لا يمكنك الذهاب لمدة 10 دقائق دون الرغبة في الاقتراض عبر نقطة انتظار في المستقبل ، ولهذا السبب في العقود الآجلة 0.1 ترى هذه Arc تظهر في كل مكان حتى تتمكن من استخدام نفس المتغير في اثنين مختلفين مكالمات and_then . لكننا قد حصلت بعيدا جدا دون أن تكون قادرة على التعبير عن المكررات ذاتية المرجع في كل شيء، انها مجرد أنه ليس المهم من حالة الاستخدام.

وظائف الخريطة هذه غير آمنة لأنه كان بإمكاني mem::swap على &mut T تمررني الوظيفة قبل إرجاع &mut U

آه ، اللعنة ، نسيت هذا الجزء منها: العابس:

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

هل يجب تسميتها as_pinned_mut و into_pinned_ref لتجنب الخلط بينها وبين الطرق التي تُرجع المراجع بالفعل ؟

تطبيقات ملحوظة لـ Unpin في الأمراض المنقولة جنسياً:

لدينا أيضًا impl<P> Unpin for Pin<P> {} . بالنسبة للأنواع التي نستخدمها ، فإن هذا ليس له أي تأثير ويبدو أنه أكثر أمانًا؟
لا تهتم ، لديك هذا في قائمتك. ؛)

ضمان السقوط

أعتقد أنه يتعين علينا تقنين ضمان Drop قبل التثبيت ، وإلا فسيكون قد فات الأوان:

من غير القانوني إبطال تخزين كائن مثبت (هدف مرجع Pin ) بدون استدعاء drop على الكائن.

يمكن أن تعني كلمة "Invalidate" هنا "إلغاء التخصيص" ، ولكن أيضًا "تغيير الغرض": عند تغيير x من Ok(foo) إلى Err(bar) ، يتم إبطال تخزين foo .

يترتب على ذلك ، على سبيل المثال ، أنه يصبح من غير القانوني إلغاء تخصيص Pin<Box<T>> أو Pin<Rc<T>> أو Pin<Arc<T>> بدون استدعاء drop::<T> .

تغيير الغرض من Deref ، DerefMut

ما زلت أشعر بعدم الارتياح إلى حد ما بشأن الكيفية التي يعيد بها هذا استخدام سمة Deref لتعني "هذا مؤشر ذكي" نحن نستخدم Deref لأشياء أخرى أيضًا ، على سبيل المثال لـ "الميراث". قد يكون هذا نمطًا مضادًا ، لكنه لا يزال شائع الاستخدام إلى حد ما ، وبصراحة ، فهو مفيد. :د

أعتقد أن هذه ليست مشكلة سلامة رغم ذلك.

فهم Unpin

المكونات الوقحة: لقد كتبت منشورتين في المدونة حول هذا الأمر ، قد يساعدان أو لا يعتمدان على مدى استمتاعك بقراءة بناء الجملة (شبه) الرسمي. ؛) تغيرت واجهات برمجة التطبيقات منذ ذلك الحين ، لكن الفكرة الأساسية لم تتغير.

إسقاطات دبوس آمنة

@ Matthias247 أعتقد أن إحدى المشكلات التي تواجهها هي أن بناء التجريدات التي تتضمن تثبيتًا حاليًا يتطلب دائمًا رمزًا غير آمن. لا بأس باستخدام هذه الأفكار التجريدية ، ولكن على سبيل المثال ، لن ينجح تحديد مُجمع مستقبلي في كود آمن. والسبب في ذلك هو أن "إسقاطات الدبوس" بها قيود لا يمكننا التحقق منها بأمان إلا من خلال تغييرات المترجم. على سبيل المثال ، أنت تسأل

لماذا تأخذ طريقة Drop () الخاصة بي الآن & mut self بدلاً من Pin.

حسنًا ، drop() قديم - إنه موجود منذ Rust 1.0 - لذلك لا يمكننا تغييره. نود أن نجعل الأمر يأخذ Pin<&mut Self> ، ثم يمكن أن تحصل أنواع Unpin على &mut كما يفعلون الآن ، لكن هذا تغيير غير متوافق مع الإصدارات السابقة.

لجعل كتابة أدوات الدمج المستقبلية آمنة ، سنحتاج إلى إسقاطات دبوس آمنة ، ولهذا علينا تغيير المترجم ، لا يمكن القيام بذلك في مكتبة. يمكننا القيام بذلك تقريبًا في proc_macro derive ، باستثناء أننا سنحتاج إلى طريقة لتأكيد "هذا النوع لا يحتوي على أي تنفيذ لـ Drop أو Unpin ".

أعتقد أن الأمر يستحق الجهد المبذول لمعرفة كيفية الحصول على واجهة برمجة تطبيقات آمنة لإسقاطات الدبوس. ومع ذلك ، لا يجب أن يمنع ذلك التثبيت: يجب أن تكون واجهة برمجة التطبيقات التي نستقر هنا متوافقة مع إسقاطات الدبوس الآمن. (قد يتعين أن يصبح Unpin عنصرًا lang لتنفيذ التأكيد أعلاه ، لكن هذا لا يبدو سيئًا للغاية.)

التثبيت ليس كذلك !

غالبًا ما كنت أفكر في C ++ ، حيث يتم تجنب معظم هذه المشكلات: يمكن الإعلان عن الأنواع غير المنقولة عن طريق حذف مُنشئ النقل وعامل التعيين. عندما يكون نوع ما غير قابل للنقل ، فإن الأنواع التي تحتوي على هذا النوع ليست كذلك.

كانت هناك عدة محاولات لتحديد الأنواع غير المتحركة لـ Rust. يصبح الأمر معقدًا جدًا بسرعة كبيرة.

شيء واحد مهم هو أن نفهم أن التدبيس لا توفر أنواع غير قابلة للنقل! تظل جميع الأنواع قابلة للحركة في الصدأ. إذا كان لديك T ، فيمكنك نقله إلى أي مكان تريده. بدلاً من الأنواع غير المنقولة ، نستفيد من قدرة Rust على تحديد واجهات برمجة تطبيقات مغلفة جديدة ، حيث نحدد نوع المؤشر الذي لا يمكنك الخروج منه . كل السحر يكمن في نوع المؤشر ( Pin<&mut T> ) ، وليس في النقطة ( T ). لا توجد طريقة لنوع ما ليقول "لا يمكنني التحرك أبدًا". ومع ذلك، هناك طريقة لنوع ليقول "إذا حصلت معلقة، لا تتحرك لي مرة أخرى". لذلك MyFuture التي أملكها سيكون دائما المنقولة، ولكن Pin<&mut MyFuture> هو مؤشر إلى مثيل MyFuture التي لا يمكن الحصول على نقل أكثر من ذلك.

هذه نقطة دقيقة ، وربما يجب أن نقضي بعض الوقت في توضيح المستندات هنا للمساعدة في تجنب سوء الفهم الشائع جدًا.

لكننا قطعنا شوطاً طويلاً دون أن نكون قادرين على التعبير عن المكرر الذاتي المرجعي على الإطلاق ، إنها ليست مهمة لحالة الاستخدام.

هذا لأنه ، حتى الآن ، تم تعريف جميع التكرارات باستخدام نوع وكتلة impl Iterator for … . عندما تحتاج الحالة إلى الإبقاء عليها بين تكرارين ، فلا يوجد خيار سوى تخزينها في حقول من نوع المكرر والعمل مع &mut self .

ومع ذلك ، حتى لو لم يكن هذا هو الدافع الأساسي لتضمين المولدات في اللغة ، فسيكون من الجيد جدًا أن تكون قادرًا في النهاية على استخدام المولد yield لتعريف شيء يمكن استخدامه مع for حلقة yield لأنه لا يقل أهمية عن مولدات التكرار كما هو الحال بالنسبة للعقود الآجلة للمولدات.

(قد يتعين أن يصبح Unpin عنصرًا lang لتنفيذ التأكيد أعلاه ، لكن هذا لا يبدو سيئًا للغاية.)

Unpin و Pin عناصر lang لدعم المولدات الثابتة الآمنة.

طيب شكرا على التفسيرات كلها! أتفق مع Gankro في أن فصلًا بأسلوب nomicon عن Pin وهذا سيكون مفيدًا بشكل كبير هنا. أظن أن هناك الكثير من تاريخ التطوير لسبب وجود العديد من الأساليب الآمنة ولماذا الأساليب غير الآمنة غير آمنة وما إلى ذلك.

في محاولة لمساعدة نفسي على فهم هذا على الرغم من أنني أردت المحاولة مرة أخرى لكتابة سبب أمان كل وظيفة أو سبب كونها unsafe . مع الفهم من أعلاه ، لدي كل ما يلي ، ولكن هناك بعض الأسئلة هنا وهناك. إذا كان بإمكان الآخرين مساعدتي في ملء هذا فسيكون ذلك رائعًا! (أو ساعدني في توضيح مكان تفكيري بشكل خاطئ)

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

    • هذه طريقة آمنة لإنشاء Pin<P> ، وأثناء وجود
      يعني Pin<P> عادةً أنه لن يتم نقل P::Target مرة أخرى في
      البرنامج P::Target ينفذ Unpin والذي يُقرأ "ضمانات
      Pin لم يعد يحمل ". ونتيجة لذلك ، فإن الأمان هنا لأنه لا يوجد
      يضمن التمسك ، بحيث يمكن المضي قدمًا في كل شيء كالمعتاد.
  • unsafe fn new_unchecked(P) -> Pin<P> where P: Deref

    • على عكس السابقة ، هذه الوظيفة هي unsafe لأن P ليس كذلك
      بالضرورة تنفيذ Unpin ، لذا يجب أن يدعم Pin<P> ضمان ذلك
      لن يتحرك P::Target مرة أخرى أبدًا بعد إنشاء Pin<P> .

    تبدو طريقة تافهة لانتهاك هذا الضمان ، إذا كانت هذه الوظيفة آمنة
    مثل:

    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
    }
    

    وبالتالي ، فإن الأمر متروك للمستخدم لضمان أن Pin<P> يعني بالفعل
    P::Target مرة أخرى بعد الإنشاء ، لذا فهو unsafe !

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

    • بالنظر إلى Pin<P> فإننا نضمن أن P::Target لن يتحرك أبدًا. هذا
      جزء من عقد Pin . نتيجة لذلك يعني ذلك بشكل تافه
      &P::Target ، سيوفر "مؤشر ذكي" آخر لـ P::Target نفس الشيء
      ضمان ، لذلك يمكن ترجمة &Pin<P> بأمان إلى Pin<&P::Target> .

    هذه طريقة عامة للانتقال من Pin<SmartPointer<T>> إلى Pin<&T>

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

    • أعتقد أن الأمان هنا جميعًا تقريبًا مثل as_ref أعلاه.
      نحن لا نقدم وصولًا متغيرًا ، فقط Pin ، لذلك لا شيء يمكن أن يكون بسهولة
      انتهكت حتى الان.

    سؤال : ماذا عن أداة ضمنية DerefMut "ضارة"؟ هذه طريقة آمنة
    للاتصال بمستخدم مقدم من المستخدم DerefMut والذي يقوم بصناديق &mut P::Target أصلاً ،
    على الأرجح السماح لها بتعديلها أيضًا. كيف هذا آمن؟

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

    • السؤال : معطى Pin<P> (وحقيقة أننا لا نعرف أي شيء عنها
      Unpin ) ، ألا يجب أن يضمن هذا عدم تحرك P::Target أبدًا؟ اذا قدرنا
      أعد تهيئته باستخدام P::Target ، مع ذلك ، ألا يجب أن يكون هذا غير آمن؟
      أم أن هذا مرتبط بطريقة ما بالمدمرات وكل ذلك؟
  • unsafe fn map_unchecked<U, FnOnce(&T) -> &U>(Pin<&'a T>, f: F) -> Pin<&'a U>

    • هذه دالة unsafe لذا فإن السؤال الرئيسي هنا هو "لماذا ليس هذا
      آمن "؟ مثال على انتهاك الضمانات إذا كانت آمنة يبدو كما يلي:

    ...

    سؤال :: ما هو المثال المضاد هنا؟ إذا كان هذا آمنًا ، فما هو
    المثال الذي يوضح مخالفة ضمانات Pin ؟

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

    • ضمان Pin<&T> يعني أن T لن يتحرك أبدًا. إرجاع &T
      لا يسمح بتحور T ، لذلك يجب أن يكون آمنًا أثناء التمسك
      هذا الضمان.

    واحد "ربما مسكت" هنا هو التحول الداخلي ، ماذا لو كان T كان
    RefCell<MyType> ؟ هذا ، ومع ذلك ، لا ينتهك ضمانات
    Pin<&T> لأن الضمان ينطبق فقط على T ككل ، وليس
    المجال الداخلي MyType . في حين أن التحور الداخلي يمكن أن يتحرك
    داخليًا ، لا يزال بشكل أساسي غير قادر على تحريك الهيكل بأكمله خلف ملف
    مرجع & .

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

    • يعني Pin<&mut T> أن T لن يتحرك أبدًا. نتيجة لذلك فهذا يعني Pin<&T>
      يوفر نفس الضمان. لا ينبغي أن يكون هناك مشكلة كبيرة في هذا التحويل ،
      انها في الغالب تبديل الأنواع.
  • unsafe fn get_unchecked_mut(Pin<&'a mut T>) -> &'a mut T

    • يعني Pin<&mut T> أن T يجب ألا يتحرك أبدًا ، لذلك هذا ضئيل جدًا unsafe
      لأنه يمكنك استخدام mem::replace في النتيجة لنقل T (بأمان). ال
      unsafe هنا "على الرغم من أنني أعطيك &mut T ، لا يُسمح لك بذلك على الإطلاق
      نقل T ".
  • unsafe fn map_unchecked_mut<U, F: FnOnce(&mut T) -> &mut U>(Pin<&'a mut T>, f: F) -> Pin<&'a mut U>

    • أعتقد أن unsafe هنا هو في الأساس على الأقل نفس ما ورد أعلاه ، نحن
      تسليم &mut T بأمان (لا يتطلب إغلاقًا غير آمن) وهو ما يمكن
      يمكن استخدامها بسهولة مع mem::replace . ربما يكون هناك عدم أمان آخر هنا أيضًا
      مع الإسقاط ، ولكن يبدو من المعقول أنه غير آمن على الأقل
      بسبب ذلك.
  • fn get_mut(Pin<&'a mut T>) -> &'a mut T where T: Unpin

    • من خلال تنفيذ Unpin هناك نوع يقول " Pin<&mut T> ليس لديه ضمانات ، إنه
      مجرد غلاف من نوع جديد &mut T ". نتيجة لذلك ، بدون ضمانات
      التمسك ، يمكننا إرجاع &mut T بأمان
  • impl<P: Deref> Deref for Pin<P> { type Target = P::Target }

    • يمكن تنفيذ ذلك بأمان باستخدام as_ref متبوعًا بـ get_ref ، لذا فإن ملف
      سلامة هذا ضمني يتبع ما سبق.
  • impl<P: DerefMut> DerefMut for Pin<P> where T::Target: Unpin { }

    • يمكن تنفيذ هذا بأمان باستخدام as_mut متبوعًا بـ get_mut ، لذا فإن ملف
      سلامة هذا ضمني يتبع ما سبق.
  • impl<T: ?Sized> Unpin for Box<T> (والتطبيقات الأخرى ذات الصلة بالمؤشر)

    • إذا لم يتم اتخاذ أي إجراء آخر ، فإن Box<T> Unpin سيطبق السمة
      فقط إذا نفذ T Unpin . هذا التنفيذ هنا يقنن ذلك حتى
      إذا لم ينفذ T صراحة Unpin ، فإن Box<T> ينفذ Unpin .

    سؤال : ما هو مثال على ما هو تمكين بشكل أساسي؟

    على سبيل المثال ، ما يمكن أن يتطلب الخزنة unsafe إذا كان هذا يعني

    لا يوجد.


@ Matthias247 لا يمكنك الحصول على & mut T بأمان من Pin

> إذا لم يكن T Unpin لأنه عندئذٍ يمكنك mem :: swap لتحريك T من الدبوس ، الأمر الذي قد يهزم الغرض من تثبيت الأشياء.

شكر! نعم ، نظرًا لأن swap ليست طريقة غير آمنة ، فمن الواضح أنها مشكلة. ولكن هل يمكن إصلاح ذلك بإضافة Unpin مرتبط بـ swap() ؟ نظرًا لأن جميع الرموز حتى الآن يجب أن تكون Unpin أو أنها غير آمنة على أي حال ، فلا ينبغي أن يؤدي ذلك إلى كسر أي شيء.

أعتقد أن أحد الأشياء التي لا تزال تربك أكثر هو أن Pin<T> يقنن ضمانات متعددة: أن عنوان T مستقر ، بالإضافة إلى بعض الضمانات حول حالته الداخلية (إنه نوع من التجميد / غير قابل للتغيير في بعض المواقف ، ولكن أيضًا ليس حقًا).

بدا لي أن نقل الكود / الإسقاطات غير الآمنة فقط إلى الأماكن التي تتطلب مكالمات أخرى على أساس Pin (على سبيل المثال في poll s في الحقول) قد يكون أفضل للتعامل مع تلك التوقعات غير الآمنة في جميع الحالات. ومع ذلك ، أدركت الآن أيضًا أن هناك مشكلة أخرى في ذلك: يمكن للكود الذي لديه حق الوصول إلى المرجع القابل للتغيير أن يتحرك في الحقل بحرية ، وعندما يتم استدعاء drop() بأمان في هذا الحقل ، فقد يتعطل بسبب ذلك يتم تخزين العنوان في مكان آخر. من أجل ذلك ، ستكون هناك حاجة إلى التحميل الزائد drop(Pin<T>) الذي تم الحديث عنه.

RalfJung شكرا Unpin و Unpin العقود الآجلة) ، يبدو ذلك أفضل. نظرًا لأنني لم أحاول ذلك ، لا يمكنني القول ما إذا كان الأمر كذلك حاليًا. أعتقد أنه لا يزال يتعين على المرء إضافة حدود Unpin على الأقل يدويًا.

أفهم أيضًا حقيقة أن الأنواع غير المنقولة تختلف عن نوع الدبوس. ومع ذلك فأنا حاليًا أكثر تركيزًا على حالات الاستخدام من الاختلاف. وبالنسبة لحالة استخدام المجموعات المتطفلة ، تعمل الأنواع غير المتحركة بشكل جيد للغاية دون إدخال الكثير من التعقيد. بالنسبة للعقود الآجلة ، من الواضح أن بعض الأبحاث ستكون مطلوبة ، لأنها تنتقل من نوع متحرك إلى نوع غير متحرك. إذا لم تكن هذه الطريقة أكثر راحة من واجهات برمجة تطبيقات Pin ، فلن يكون هناك فوز أيضًا.

إن إضافة T: Unpin إلى mem::swap يعني أنه لا يمكن استخدامها على أنواع معينة حتى عندما لا تكون داخل Pin.

ولكن هل يمكن إصلاح ذلك عن طريق إضافة Unpin ملزم بالمبادلة ()؟ نظرًا لأن جميع التعليمات البرمجية حتى الآن يجب أن تكون Unpin أو غير آمنة على أي حال ، فلا ينبغي أن يكسر هذا أي شيء.

سيؤدي ذلك إلى كسر جميع الكود العام: إذا كتبت دالة في الصدأ المستقر اليوم مقابل بعض T بدون قيود ، يمكنك استدعاء swap عليها. هذا يجب أن يستمر في العمل.

تعمل الأنواع غير القابلة للحركة بشكل جيد للغاية دون إدخال الكثير من التعقيد.

لم يوضح أحد طريقة لإضافة أنواع غير متحركة إلى الصدأ بطريقة متوافقة مع الإصدارات السابقة دون تعقيد يتجاوز بشكل كبير ما هو مقترح للتثبيت هنا. يجب أن تجد بعضًا من هذه المقترحات والمناقشات القديمة في RFC repo. راجع https://github.com/rust-lang/rfcs/pull/1858 للحصول على مثال واحد.

يجب أن تساعد RFC على https://github.com/rust-lang/rfcs/pull/2349 بالإضافة إلى سلسلة مدونة القارب التي تبدأ من هنا في منحك بعض الخلفية وبعض الانطباعات عن التصميمات الأخرى التي تم النظر فيها. (لاحظ أيضًا التواريخ ، كان هذا التصميم قيد التشغيل منذ ما يقرب من 10 أشهر!)

كما أن mem :: swap عبارة عن ترنجة حمراء ، لأنها ليست وظيفة مثيرة للاهتمام على الإطلاق. انها مجرد حرفيا

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

Gankro ألا يستخدم رمزًا غير آمن؟ افايك لا يمكن كتابة ذلك حرفيا.

تحرير: أعتقد أن هناك طريقة أخرى للتفكير في ذلك وهي أن إضافة T: Unpin إلى mem::swap يغير بالفعل تعريف الأمان على مستوى اللغة. سيؤدي ذلك إلى كسر جميع fns mycrate::swap في البرية.

إضافة T: Unpin to mem :: swap قد يعني أنه لا يمكن استخدامها على أنواع معينة حتى عندما لا تكون داخل Pin.

إذا تم اشتقاق Unpin تلقائيًا (بنفس الطريقة مثل Sync / Send ) ، فأعتقد أن هذا لا ينبغي أن يكون مشكلة.

سيؤدي ذلك إلى كسر كل الكود العام: إذا كتبت دالة في الصدأ المستقر اليوم لبعض T دون قيود ، فيمكنك استدعاء swap عليها. هذا يجب أن يستمر في العمل.

لكن من الواضح أن هذا هو. لم أفكر في حقيقة أن حدود السمات تحتاج إلى نشر صريح في Rust.

لم يبرهن أحد على طريقة لإضافة أنواع غير متحركة إلى الصدأ بطريقة متوافقة مع الإصدارات السابقة دون تعقيد يتجاوز بشكل كبير ما هو مقترح للتثبيت هنا. يجب أن تجد بعضًا من هذه المقترحات والمناقشات القديمة في RFC repo. انظر rust-lang / rfcs # 1858 للحصول على مثال واحد.

شكرًا ، سأقرأ المزيد عن العمل السابق حول هذا إذا وجدت بعض الوقت. من الواضح أن الكثير من الأفكار والجهود قد بُذلت بالفعل في هذا الأمر ، وأنا بالتأكيد لا أريد منع الأشياء. أردت فقط تقديم مخاوفي وأسئلتي عند محاولة العمل مع هذا.

MustafaHosny اللهم امين

إذا تم اشتقاق Unpin تلقائيًا (بنفس الطريقة مثل Sync / Send) ، فأعتقد أن هذا لا ينبغي أن يكون مشكلة.

لست متأكدًا مما إذا كنت واضحًا. للتوضيح ، من الآمن تمامًا التنقل حول نوع !Unpin وبالتالي آمن تمامًا إلى mem::swap حولهم. من غير الآمن فقط نقل نوع T: !Unpin بعد تثبيته ، أي داخل Pin<P<T>> .

على سبيل المثال ، في التعليمات البرمجية غير المتزامنة / انتظار ، يمكنك التنقل حول العقود الآجلة التي يتم إرجاعها من وظيفة غير متزامنة بقدر ما تريد. لن تكون قادرًا على نقلهم إلا بمجرد أن تحصل على pin_mut! لهم أو تضعهم في Pin<Box<..>>> أو غير ذلك.

لدي بعض الأسئلة المتنوعة حول هذا:

  1. نظرًا لأهمية Pin<T> لـ async وللمولدات واحتمالية عدم الأمان عند التفاعل مع أجزاء أخرى من الصدأ (على سبيل المثال swap & replace ) ، أي تم إجراء التحقق الرسمي (على سبيل المثال من خلال jhjourdan أوRalfJung) من متغير واجهة برمجة تطبيقات التثبيت المقترحة هنا؟

  2. هل تقدم واجهة برمجة التطبيقات هذه أي ضمانات جديدة حول الآلة المجردة / الدلالات التشغيلية لـ Rust؟ أي ، إذا نسينا حالة الاستخدام كآلية دعم لـ async & await / للمولدات ، هل يمكننا وضع هذا داخل صندوق في النظام البيئي وسيعمل فقط في ضوء الضمانات الحالية نحن يعطى؟

  3. ما نوع واجهات برمجة التطبيقات أو إضافات النظام التي تصبح مستحيلة كنتيجة لتثبيت API؟ (هذا السؤال امتداد لـ 2.)

  4. ما هي السبل التي توفرها واجهة برمجة التطبيقات (API) المستقرة من حيث تطويرها بلغة توفر &pin T نوعًا لتحسين الإسقاط الميداني وما شابه (والذي لا يبدو رائعًا مع واجهة برمجة التطبيقات المقترحة).

لدي بعض الملاحظات المتنوعة:

  1. يبدو أن الوثائق في المكتبة القياسية متناثرة للغاية. :(

  2. أتفق مع الآخرين في أن بنية التثبيت مرهقة / معقدة عقليًا.

  3. يبدو المثال Unmovable في التوثيق معقدًا للغاية ويتضمن unsafe ؛ هذا يبدو دون المستوى الأمثل. مع التهيئة التدريجية كما هو موضح في مسودة RFC في اللغة (أي تحسين على NLL) يمكن بدلاً من ذلك أن تعطينا:

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.

هذا لا ينطوي على أي شيء غير آمن ومن السهل جدًا على المستخدم التعامل مع هذا.

بالإضافة إلى ذلك ، لا توفر واجهات برمجة تطبيقات الأمراض المنقولة جنسياً طريقة آمنة لتثبيت الكائنات في المكدس.
هذا لأنه لا توجد طريقة لتنفيذ ذلك بأمان باستخدام وظيفة API.

ماذا عن API مثل هذا؟

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)
}

لم أتابع تطوير واجهات برمجة التطبيقات المثبتة عن كثب ، لذلك كان من الممكن ذكر ذلك أو شرحه في مكان آخر ولم أتمكن من العثور عليه ، أعتذر إذا كان هذا هو الحال:

النوع Pinned هو نوع ZST الذي لا يطبق Unpin ؛ يسمح لك
قم بإلغاء التنفيذ التلقائي لـ Unpin على المستقر ، حيث يشير !Unpin
لن تكون مستقرة بعد.

هل يوجد تفسير في أي مكان حول سبب عدم إمكانية جعل الضمانات !Unpin مستقرة؟

يكون آمنًا فقط إذا كان Foo (النوع المحتوي) غير مكرر (معبأ) ،
لأن هذا يتسبب في نقل الحقول لإعادة تنظيمها.

هل تعني "معبأة" إمكانية نقل الحقول ديناميكيًا؟ هذا مخيف بعض الشيء. هل نحن على يقين من أن llvm لن يقوم أبدًا بإنشاء رمز لنقل الحقول في ظروف أخرى؟ وبالمثل ، هل من الممكن أن يتم نقل القيم المثبتة على المكدس بواسطة llvm؟

على الرغم من الدقة ، يبدو هذا وكأنه واجهة برمجة تطبيقات لطيفة حقًا. عمل جيد!

Centril Ralf كتب عن في مدونته .

لم تتضمن واجهات برمجة التطبيقات pin API أي تغييرات في اللغة على الإطلاق ، ويتم تنفيذها بالكامل في المكتبة القياسية باستخدام ميزات اللغة الموجودة مسبقًا. ليس له أي تأثير على Rust على اللغة ولا يمنع أي ميزة لغة أخرى.

Pin هو مجرد تنفيذ ذكي لواحدة من أكثر ميزات Rust قيمة وكلاسيكية: القدرة على إدخال الثوابت إلى واجهة برمجة التطبيقات عن طريق تعليم جزء من API unsafe . يلف Pin مؤشرًا لجعل عملية واحدة ( DerefMut ) غير آمنة ، مما يتطلب من الأشخاص الذين يقومون بذلك دعم بعض الثوابت (ألا يخرجوا عن المرجع) ، والسماح للكود الآخر افترض أن هذا لن يحدث أبدًا. مثال مشابه وأقدم بكثير لهذه الخدعة هو String ، مما يجعل وضع وحدات بايت غير UTF8 في سلسلة غير آمنة ، مما يسمح للكود الآخر بافتراض أن جميع البيانات الموجودة في String هي UTF8.

هل هناك تفسير في أي مكان حول السبب!

الضمانات السلبية غير مستقرة حاليًا وغير مرتبطة تمامًا بواجهات برمجة التطبيقات هذه.

الضمانات السلبية غير مستقرة حاليًا.

🤦‍♂️ هذا منطقي ، كان ينبغي التفكير في ذلك لفترة أطول قليلاً. شكر.

alexcrichton هذا بعض التحليلات الرائعة لواجهة برمجة التطبيقات هذه ، يجب أن نحاول الاحتفاظ بها في مكان ما أفضل من بعض التعليقات التي ستضيع!

بعض التعليقات:

as_mut : سؤال: ماذا عن أداة DerefMut "الخبيثة"؟ هذه طريقة آمنة
لاستدعاء DerefMut المقدم من المستخدم والذي يقوم بصناديق & mut P :: Target محليًا ،
على الأرجح السماح لها بتعديلها أيضًا. كيف هذا آمن؟

بشكل أساسي ، عندما تتصل بـ new_unchecked ، فإنك تقدم وعدًا بشأن تنفيذ Deref و DerefMut لهذا النوع.

set :

(وحقيقة أننا لا نعرف أي شيء عنها
Unpin) ، ألا يجب أن يضمن هذا عدم تحرك P :: Target أبدًا؟ اذا قدرنا
أعد تهيئته مع P :: Target آخر ، رغم ذلك ، ألا يجب أن يكون هذا غير آمن؟
أم أن هذا مرتبط بطريقة ما بالمدمرات وكل ذلك؟

يؤدي هذا إلى إسقاط المحتوى القديم للمؤشر ، ويضع محتوى جديدًا فيه. "مثبت" لا يعني "لم يتم إسقاطه مطلقًا" ، بل يعني "لم يتم نقله حتى يتم إسقاطه". لذا فإن إسقاطها أو الكتابة فوقها أثناء استدعاء drop أمر جيد. استدعاء drop أمر بالغ الأهمية ، وهذا هو ضمان الإسقاط الذي ذكرته أعلاه.

أين ترى شيئًا يتحرك هنا؟

map_unchecked : سؤال :: ما هو المثال المضاد هنا؟ إذا كان هذا آمنًا ، فما هو المثال الذي يظهر انتهاكًا لضمانات Pin؟

من الأمثلة على ذلك البدء بـ Pin<&&T> واستخدام هذه الطريقة للحصول على Pin<&T> . التثبيت لا "ينتشر من خلال" المراجع.

get_ref : واحد "ربما مسكت" هنا هو قابلية التغيير الداخلية ، ماذا لو كان T.
RefCell؟

في الواقع ، هذا مسكتك ، ولكن كما لاحظت ليست مشكلة سلامة. ما قد يكون غير سليم هو وجود طريقة تتراوح من Pin<RefCell<T>> إلى Pin<&[mut] T> . ما يحدث أساسًا هو أن RefCell لا ينشر التثبيت ، يمكننا impl<T> Unpin for RefCell<T> .

هل تم إجراء أي تحقق رسمي (على سبيل المثال بواسطة jhjourdan أوRalfJung) من متغير واجهة برمجة تطبيقات التثبيت المقترحة هنا؟

لا ، ليس من جانبنا. تحتوي منشورات المدونة التي ذكرتها أعلاه على بعض الأفكار حول كيفية البدء في إضفاء الطابع الرسمي على هذا ، لكننا لم نقم بذلك بالفعل. إذا أعطيتني آلة الزمن أو طالب دكتوراه مهتمًا ، فسنقوم بذلك. ؛)

إذا نسينا حالة الاستخدام كآلية دعم للمولدات غير المتزامنة والانتظار / ، فهل يمكننا وضع هذا داخل صندوق في النظام البيئي وسيعمل فقط في ضوء الضمانات الحالية التي نقدمها؟

هذه هي النية.

ما نوع واجهات برمجة التطبيقات أو إضافات النظام التي تصبح مستحيلة كنتيجة لتثبيت API؟ (هذا السؤال امتداد لـ 2.)

أه ليس لدي أدنى فكرة كيف أجيب على هذا السؤال بأي ثقة. مساحة الإضافات المحتملة كبيرة جدًا وعالية الأبعاد أيضًا لدرجة أنني أجرؤ على إصدار أي نوع من التصريحات العالمية عنها.

ما هي السبل التي توفرها واجهة برمجة التطبيقات (API) المستقرة من حيث تطويرها لغة مقدمة ونوع دبوس T لتحسين الإسقاط الميداني وما إلى ذلك (والذي لا يبدو رائعًا مع واجهة برمجة التطبيقات المقترحة).

لست متأكدًا بعد الآن بشأن &pin T ، فهو لا يتطابق بشكل جيد مع Pin<T> . فيما يتعلق بمعالجة التوقعات ، سنحتاج إلى بعض الاختراق لنقول "لم يتم تنفيذ Unpin و Drop لهذا النوع" ، ثم يمكننا القيام بذلك بأمان باستخدام ماكرو. للحصول على بيئة عمل إضافية ، من المحتمل أن نرغب في إمكانية "عرض ميداني" عام في اللغة ، والتي من شأنها أيضًا أن تغطي الانتقال من &Cell<(A, B)> إلى &Cell<A> .

هل هناك تفسير في أي مكان حول السبب!

تحتوي الضمانات السلبية لـ AFAIK على بعض القيود طويلة الأمد ، وإذا أضفت حدودًا عامة إليها ، فلن تعمل غالبًا بالطريقة التي تعتقد أنها يجب أن تعمل بها. (في بعض الأحيان يتم تجاهل الحدود العامة أو نحو ذلك).

ربما يصلح Chalk كل هذا ، ربما بعضًا منه فقط ، ولكن في كلتا الحالتين ربما لا نريد حظر هذا على Chalk.

هل تعني "معبأة" إمكانية نقل الحقول ديناميكيًا؟ هذا مخيف بعض الشيء.

إنها الطريقة الصحيحة الوحيدة لاستدعاء drop في حقل معبأ ، بالنظر إلى أن drop يتوقع مرجعًا محاذيًا.

هل نحن على يقين من أن llvm لن يقوم أبدًا بإنشاء رمز لنقل الحقول في ظروف أخرى؟ وبالمثل ، هل من الممكن أن يتم نقل القيم المثبتة على المكدس بواسطة llvm؟

يجب ألا يكون نسخ LLVM للبايت مشكلة ، لأنه لا يمكن تغيير سلوك البرنامج. يتعلق هذا بمفهوم مستوى أعلى لنقل البيانات ، بطريقة يمكن ملاحظتها في Rust (على سبيل المثال ، لأن المؤشرات إلى البيانات لم تعد تشير إليها). لا يمكن لـ LLVM فقط نقل البيانات إلى مكان آخر قد يكون لدينا مؤشرات إليه. وبالمثل ، لا يمكن لـ LLVM فقط نقل القيم على المكدس التي تم أخذ عناوينها.

حسنًا ، شكرًا RalfJung ، هذا منطقي! بعض أسئلة المتابعة ...

عندما تقول "لم يتم نقله حتى إسقاطه" ، فهذا يعني أنه قد يتم استدعاء Drop حيث تم نقل &mut self من عنوان Pin<&mut Self> ؟ لا تستطيع المدمرات الاعتماد على دقة المؤشرات الداخلية ، أليس كذلك؟

كان قلقي عند النظر إلى set هو كيفية التعامل مع الذعر ، لكنني أعتقد أن هذه ليست مشكلة بعد البحث في codegen أكثر قليلاً.

عندما تقول "لم يتم نقله حتى إسقاطه" ، فهذا يعني أنه قد يتم استدعاء Drop حيث تم نقل &mut self من عنوان Pin<&mut Self> ؟ لا تستطيع المدمرات الاعتماد على دقة المؤشرات الداخلية ، أليس كذلك؟

alexcrichton كان ما فهمته أن هذا يعني أنه لم يتم نقله أبدًا إلا بعد إرجاع Drop::drop . وإلا فإن بعض حالات الاستخدام (المجموعات المتطفلة ومخازن DMA المخصصة للمكدس على الأقل) تصبح مستحيلة.

يمكن للمدمرين الاعتماد على شيء لم يتم نقله أبدًا إذا تمكنوا من إثبات أنه كان في السابق بـ Pin . على سبيل المثال ، إذا كان بإمكان آلة الحالة إدخال حالة فقط من خلال واجهة برمجة التطبيقات التي تتطلب تثبيتها ، فيمكن للمُدمِّر أن يفترض أنه تم تثبيته قبل إسقاطه إذا كان في تلك الحالة.

لا يمكن للكود أن يفترض أن المدمرين ينقلون الأعضاء ، ولكن من الواضح أنه يمكنك افتراض أن المدمرين لا يحركون الأشياء لأنك الشخص الذي يكتبها.

عندما تقول "لم تتحرك أبدًا حتى تم إسقاطها" ، فهذا يعني أنه قد يتم استدعاء Drop حيث تم نقل & mut self من عنوان Pin <& mut Self>؟ لا تستطيع المدمرات الاعتماد على دقة المؤشرات الداخلية ، أليس كذلك؟

أعني أن البيانات لن تتحرك أبدًا (بمعنى عدم الانتقال إلى أي مكان آخر ، بما في ذلك عدم التخصيص) حتى يتم استدعاء drop . ونعم ، يمكن أن يعتمد drop على التشغيل على الموقع المثبت ، على الرغم من أن نوعه لا يمكنه التعبير عن ذلك. يجب أن يأخذ drop Pin<&mut self> (لجميع الأنواع) ، لكن للأسف ، فات الأوان لذلك.

بعد استدعاء drop ، تصبح البيانات مجرد بايتات لا معنى لها ، يمكنك فعل أي شيء بها: ضع أشياء جديدة هناك ، أو ألغِ تخصيصها ، أو أيًا كان.

يسمح هذا ، على سبيل المثال ، بقائمة مرتبطة متطفلة حيث يقوم مدمر عنصر بإلغاء تسجيله عن طريق ضبط المؤشرات المجاورة. نحن نعلم أن الذاكرة لن تختفي دون استدعاء ذلك المدمر. (لا يزال من الممكن تسريب العنصر ، وبعد ذلك سيبقى في تلك القائمة المرتبطة إلى الأبد. ولكن في هذه الحالة سيبقى ذاكرة صالحة لذلك لا توجد مشكلة تتعلق بالسلامة.)

لقد كنت أقرأ كل ما يمكنني العثور عليه في Pin ، Unpin ، والمناقشة التي أدت إلى كل ذلك ، وبينما أفكر الآن أنني أفهم ما يجري ، هناك أيضًا الكثير الدقة حول ما تعنيه الأنواع المختلفة ، وكذلك العقد الذي يجب على المنفذين والمستخدمين اتباعه. للأسف ، أرى القليل نسبيًا من النقاش حول ذلك في المستندات لـ std::pin أو على Pin و Unpin وجه التحديد. على وجه الخصوص ، أود أن أرى بعض المحتوى من هذه التعليقات:

دمجها في المستندات. على وجه التحديد:

  • هذا Pin يحمي فقط "مستوى واحد عميق".
  • يضع هذا Pin::new_unchecked قيودًا على الضمانات لـ Deref و DerefMut .
  • التفاعل بين Pin و Drop .
  • كيف لا يُسمح فقط لـ !Unpin بالتحرك بمجرد وضعه في Pin .
  • الأساس المنطقي لماذا Pin<Box<T>>: Unpin where T: !Unpin . هذا يعود إلى تقييد "مستوى واحد عميق" أعلاه ، لكنني أعتقد أن هذا المثال الملموس مع شرح مناسب سيكون مفيدًا للقراء.

وجدت الأمثلة المضادة لـ alexcrichton مفيدة جدًا أيضًا. إعطاء القارئ فكرة عن ما يمكن ان تتعرض لمختلف unsafe طرق أبعد من مجرد النثر وأعتقد أن يساعد كثيرا (على الأقل فعلت بالتأكيد بالنسبة لي). بشكل عام ، نظرًا لدقة واجهة برمجة التطبيقات هذه ، أود أن أرى توسيع أقسام الأمان لمختلف الأساليب غير الآمنة ، وربما تتم الإشارة إليها أيضًا من المستندات على مستوى الوحدة النمطية std::pin .

لم أستخدم واجهة برمجة التطبيقات هذه كثيرًا حتى الآن ، لذلك سأثق في الحكم الفني الذي هو في حالة جيدة الآن. ومع ذلك ، أعتقد أن الأسماء Pin و Pinned و Unpin متشابهة جدًا وغير معبرة عن أنواع / سمات مختلفة جدًا وواجهة برمجة تطبيقات معقدة نسبيًا ، مما يجعل فهمها أكثر صعوبة (كما يتضح من بعض التعليقات على هذا الموضوع).

يبدو أنهم يتبعون اصطلاحات التسمية لسمات العلامة ، لذلك لا يمكنني الشكوى حقًا ، لكنني أتساءل عما إذا كان بإمكاننا إجراء مفاضلة بين الإسهاب وتفسير الأسماء:

  • Pinned - نوع من الارتباك لأنه نفس الكلمة مثل Pin . نظرًا لاستخدامه مثل PhantomData لزيادة بنية بمعلومات وصفية قد تكون مفقودة بخلاف ذلك ، ماذا عن PinnedData أو PhantomPinned أو PhantomSelfRef أو حتى DisableUnpin ؟ شيء يشير إلى نمط الاستخدام و / أو التأثير الذي سيكون له.
  • Unpin - كما هو الحال في https://github.com/rust-lang/rust/issues/55766#issuecomment -437266922 ، أنا مرتبك من الاسم Unpin ، لأن "un-pin "يمكن فهمه بطرق متعددة غامضة. شيء مثل IgnorePin ، PinNeutral ربما؟

عمومًا أفشل وأجد أسماء بديلة جيدة بنفسي على الرغم من ...

يبدو لي PhantomPin و PinNeutral أسمائيين لطيفة بشكل خاص.

فقط لتقديم نقطة مقابلة ، وجدت أن Unpin بديهي (بمجرد أن فهمته). Pinned الصعب الحفاظ على Pinned إلى NotUnpin ؟

أوافق على أن العثور على أسماء أفضل قد يكون تمرينًا مفيدًا لركوب الدراجات لأغراض تسهيل الحديث عن التثبيت. انا اقترح:

  • Pin -> Pinned : عندما تحصل على Pin ، فهذا يعد حقًا أن ما تم إعطاؤه _ قد تم تثبيته_ ، وسوف _ يظل_ مثبتًا إلى الأبد. لا أشعر بقوة للغاية حول هذا على الرغم، كما يمكنك _could_ أيضا الحديث عن أن يحصل على "دبوس من قيمة". Pinned<Box<T>> يقرأ بشكل أفضل بالنسبة لي ، خاصة أنه تم تثبيت Box ، وليس الأشياء التي يحتوي عليها.
  • Unpin -> Repin : لسمات العلامة الأخرى ، نتحدث عادة عن ما يمكنك فعله بشيء له تلك السمة المحددة. وهذا هو سبب اختيار Unpin في المقام الأول. ومع ذلك ، أعتقد أن ما نريد حقًا أن يأخذه القارئ هنا هو أنه يمكن تثبيت شيء ما Unpin ، ثم إعادة تثبيته في مكان آخر ، دون عواقب أو اعتبار. أحب أيضًا اقتراح @ mark-im بـ PinNeutral ، على الرغم من أنه مطول إلى حد ما.
  • Pinned -> PermanentPin : لا أعتقد أن Pinned هو اسم جيد ، لأن الشيء الذي يحتوي على Pinned ليس مثبتًا بالفعل .. إنه فقط ليس Unpin . يواجه PhantomPin مشكلة مماثلة من حيث أنه يشير إلى Pin ، عندما لا يكون Pin هو الشيء الذي تريد الوصول إليه حقًا. NotUnpin على سلبي مزدوج ، مما يجعل من الصعب التفكير فيه. اقترب طلبKimundi PhantomSelfRef من بمثيل واحد حيث يكون هذا هو الحال (عندما لديك مرجع ذاتي). يمكن أيضًا صياغة اقتراحي كـ PermanentlyPinned ؛ لا أعرف أي شكل أقل سوءًا.

أعتقد أن Pinned يجب أن ينتهي به الأمر إلى NotX حيث X أيًا كان اسم Unpin ينتهي به الأمر. المهمة الوحيدة لـ Pinned هي جعلها بحيث لا يقوم نوع التضمين بتنفيذ Unpin . (تحرير: وإذا قمنا بتغيير Unpin إلى شيء آخر ، فمن المفترض أن السالبة المزدوجة ليست مشكلة)

Repin غير منطقي بالنسبة لي ، لأن "هذا النوع يمكن تثبيته في مكان آخر" هو مجرد تأثير جانبي لـ "يمكن نقل هذا النوع من دبوس".

tikue بمعنى ما أشعر بنفس الشيء ، ولكن في الاتجاه المعاكس. أعتقد أنه يجب صياغة Unpin بالصيغة السلبية "هذا _ لا _ مقيد بـ Pin " ، بينما يجب صياغة Pinned في الإيجابي "هذا _ هو مقيد بـ Pin ". في الغالب فقط لتجنب السلبية المزدوجة. لكن هذا تفصيل. أنا أحب فكرة وجود ثنائية. ربما: s/Unpin/TemporaryPin ، s/Pinned/PermanentPin ؟

تحرير: نعم ، أرى أن وجهة نظرك حول Repin هي أحد الآثار الجانبية لـ Unpin . أردت إيصال حقيقة أن Pin "غير مهم" لنوع Unpin ، والذي لا أعتقد أن Unpin يعمل بشكل جيد للغاية. ومن هنا جاء الاقتراح أعلاه وهو TemporaryPin .

jonhoo أعتقد أن السبب الرئيسي الذي Pinned يمنع إحدى السمات من أن يتم تنفيذها ، لذلك ، بالمعنى الأكثر وضوحًا بالنسبة لي ، السلبية الحقيقية.

تحرير: ماذا عن:

Unpin -> Escape
Pinned -> NoEscape

مثير للاهتمام .. أحاول أن أرى كيف يتناسب مع الوثائق. شيء مثل:

بشكل عام ، عندما تحصل على Pin<P> ، فإن ذلك يأتي مع ضمان أن هدف P لن يتحرك حتى يتم إسقاطه. الاستثناء لهذا هو إذا كان هدف P هو Escape . تعد الأنواع التي تم تحديدها على أنها Escape أنها تظل صالحة حتى إذا تم نقلها (على سبيل المثال ، لا تحتوي على مراجع ذاتية داخلية) ، وبالتالي يُسمح لها بـ "الهروب" من Pin . Escape هي سمة تلقائية ، لذا فإن جميع الأنواع التي تتكون بالكامل من الأنواع Escape هي نفسها أيضًا Escape . يمكن للمنفذين إلغاء الاشتراك ليلاً باستخدام impl !Escape for T {} ، أو بتضمين علامة NoEscape من std::phantom .

يبدو هذا لائقًا جدًا ، على الرغم من أن الارتباط بكلمة "الهروب" يبدو ضعيفًا بعض الشيء. بشكل منفصل ، جعلتني كتابة ما ورد أعلاه أدرك أيضًا أن Pin<P> لا يضمن حقًا عدم نقل هدف P (على وجه التحديد بسبب Unpin ). بدلاً من ذلك ، تضمن أنه لا يهم إذا كان هدف P يتحرك _ أو_ P لن يتم نقل هدفه. لا أعرف كيفية استخدام ذلك للإبلاغ عن اختيار أفضل للأسماء على الرغم من ... ولكن من المحتمل أن يكون ذلك شيئًا يجب أن يتم إدخاله في المستندات بطريقة أو بأخرى.

أنا شخصياً لدي كراهية كبيرة لـ Unpin كاسم ، ربما لأنه غالبًا ما يُنظر إليه على أنه impl !Unpin والذي يقرأ "not-un-pin" ويتطلب عدة دورات ذهنية (I أنا نموذج أقدم) لاستنتاج أنه يعني "حسنًا ، سيتم تثبيت هذا النموذج إلى الأبد بمجرد تثبيته في المرة الأولى" ، لذلك لا يمكنني حتى تحسين السلبية المزدوجة.
بشكل عام ، يميل البشر إلى قضاء وقت أكثر صعوبة في التفكير في السلبيات بدلاً من الإيجابيات (بدون مصدر مباشر ، ولكن تحقق من عمل ريتشارد هدسون إذا كان لديك شك).
راجع للشغل Repin يبدو لطيفًا حقًا بالنسبة لي.

يصعب شرح Pin لأنه لا يجعل القيمة المثبتة دائمًا ثابتة. Pinned محير لأنه لا يقوم بتثبيت أي شيء. إنه يمنع فقط الهروب من Pin .

يمكن تفسير Pin<P<T>> كقيمة مثبتة: لا يمكن نقل القيم المثبتة إلا إذا كانت القيمة من النوع الذي يمكنه تجاوز الدبوس.

يبدو أن بعض عمليات البحث السريع في googling تظهر أنه في المصارعة ، عندما يتم تثبيت أحدهم ، فإن الخروج من دبوس يسمى الهروب .

أحب أيضًا مصطلح escape بدلاً من Unpin لكنني سأختار EscapePin .

الكثير من الأفكار الجيدة هنا!

شيء عام واحد: بالنسبة لي كمتحدث غير أصلي ، فإن Pin و Unpin هي في الغالب أفعال / أفعال. في حين أن Pin يبدو منطقيًا ، نظرًا لأنه يتم تثبيت الكائن في موقع ذاكرة واحد في كل مرة ، لا يمكنني رؤية الشيء نفسه لـ Unpin . بمجرد استلام مرجع Pin<&mut T> ، سيتم تثبيت T دائمًا بمعنى أن موقع الذاكرة مستقر ، سواء كان Unpin أم لا. ليس من الممكن حقًا إزالة تثبيت كائن كإجراء. الفرق هو أن الأنواع Unpin لا تتطلب ضمانات التثبيت ليتم دعمها في تفاعلات أخرى. فهي ليست مرجعية ذاتية ، ولا يتم إرسال عنوان ذاكرتهم على سبيل المثال إلى كائن آخر وتخزينه هناك.

أتفق مع tikue على أنه سيكون من الجيد أن يكون لديك عمل مذهل لما يعنيه Unpin الواقع ، لكن من الصعب تحديده. ليس الأمر مجرد أن هذه الأنواع قابلة للحركة ، كما أنها ليست مجرد افتقارها إلى المرجعية الذاتية؟ ربما يتعلق الأمر بـ "عدم إبطال أي مؤشرات في مساحة الذاكرة بالكامل عند نقل الكائن". ثم شيء مثل StableOnMoveAfterPin ، أو StableMove قد يكون خيارًا ، لكن هذه أيضًا لا تبدو رائعة حقًا.

Repin بالنسبة لي له نفس التعقيدات مثل Unpin ، وهو ما يعني أنه يتم إلغاء تثبيت شيء واحد أولاً - وهو ما لا يحدث حسب فهمي.

نظرًا لأن السمة تحدد غالبًا ما يحدث بعد أن يرى المرء Pin من النوع ، أجد أشياء مثل PinNeutral أو PinInvariant ليست سيئة للغاية.

بالنسبة إلى Pin مقابل Pinned ، أعتقد أنني أفضل Pinned ، لأن هذه هي حالة المؤشر في الوقت الذي يراه فيه المرء.

@ Matthias247 لا أعتقد أنك تضمن استقرار عنوان P::Target إذا كان P: Unpin ؟ قد أكون مخطئا في هذا رغم ذلك؟

MustafaHosny اللهم امين

بمجرد أن أتلقى مرجعًا لـ Pin <& mut T> ، سيتم تثبيت T دائمًا بمعنى أن موقع الذاكرة مستقر ، سواء كان Unpin أم لا.

هل يمكنك توضيح ما تعنيه بهذا؟ بإعطاء T: Unpin يمكنك كتابة ما يلي:

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 بالفعل سؤال جيد. كان تفكيري هو أن العقود الآجلة يتم تغليفها ، ومن ثم سيتم استدعاء طريقة poll() على نفس عنوان الذاكرة. ولكن من الواضح أن هذا ينطبق فقط على مهمة / مستقبل المستوى الأعلى ، وقد تتحرك الطبقات المتوسطة في العقود الآجلة عندما تكون Unpin . لذلك يبدو أنك على حق.

Wrt أحدث حفل زفاف:

  • Unpin : ماذا عن MoveFromPin ؟ إذا كنت لا أزال أفتقد بعض التفاصيل الدقيقة ، أعتقد أن هذا يوضح بشكل مباشر القدرة التي تتيحها السمة بالفعل: إذا كان النوع ضمن Pin ، فلا يزال بإمكانك تحريكه.

    بشكل حاسم يشير إلى نفس الشيء مثل Unpin ، لكنه مؤطر كتأكيد إيجابي ، لذلك بدلاً من السالب المزدوج !Unpin لدينا الآن !MoveFromPin . أعتقد أنني أجد ذلك أسهل في التفسير ، على الأقل ... إنه أه ، الأنواع التي لا يمكنك التخلص منها.

    (هناك مجال للتنوع في الفكرة الأساسية: MoveOutOfPin ، MoveFromPinned ، MoveWhenPinned ، وهكذا).

  • Pinned : يمكن أن يصبح هذا بعد ذلك NoMoveFromPin ، وتأثيره هو صنع نوع !MoveFromPin . أعتقد أن هذا يبدو واضحًا بدرجة كافية.

  • Pin نفسه: هذا غير متصل بالاثنين الآخرين وأيضًا ليس مهمًا ، لكن أعتقد أنه قد يكون هناك مجال لبعض التحسينات الطفيفة هنا أيضًا.

    تكمن المشكلة في أن Pin<&mut T> (على سبيل المثال) لا يعني أن &mut مثبت ، فهذا يعني أن T هو (ارتباك أعتقد أنني رأيته في دليل تعليق حديث واحد على الأقل). نظرًا لأن الجزء Pin يعمل كنوع من المُعدِّل على &mut ، أعتقد أن هناك حالة سيكون من الأفضل تسميتها Pinning .

    هناك بعض السوابق غير المباشرة لهذا: إذا أردنا تعديل دلالات الفائض لنوع عدد صحيح للالتفاف حولها بدلاً من الذعر ، نقول Wrapping<i32> بدلاً من Wrap<i32> .

كل هذه الأشياء أطول من النسخ الأصلية ، ولكن بالنظر إلى مدى حساسية بعض المنطق حولها ، فقد يكون استثمارًا مفيدًا لمزيد من الوضوح.

رد: Repin ، أتوقع أن يكون هذا شيئًا مثل

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

والتي يمكن استخدامها لدعم أنواع !Unpin داخل مجموعة تشبه Vec التي تنقل محتوياتها أحيانًا (هذا ليس اقتراحًا لإضافة مثل هذه السمة الآن أو في أي وقت ، فقط انطباعي الأول من اسم السمة).

أيضا bikshedding الأسماء:

  • Pin<P> -> Pinned<P> : القيمة التي تم تثبيت المؤشر عليها P نقطة في الذاكرة طوال عمرها (حتى يتم إسقاطها).
  • Unpin -> Moveable : لا يلزم تثبيت القيمة ويمكن نقلها بحرية.
  • Pinned (الهيكل) -> Unmoveable : يجب أن يكون Pinned ولا يمكن نقله.

لا أعتقد أن Pin أو Unpin يجب أن يتغير ، فالبدائل كلها تضيف الإسهاب دون وضوح في رأيي ، أو حتى مضللة تمامًا. لقد أجرينا هذه المحادثة بالفعل ، وتوصلنا إلى قرار باستخدام Pin و Unpin ، ولم تعد أي من الوسيطات التي تم طرحها في هذا الموضوع جديدة.

ومع ذلك ، تمت إضافة Pinned منذ المناقشة السابقة ، وأعتقد أنه من المنطقي جعلها PhantomPinned لتوضيح نوع العلامة الوهمية مثل PhantomData .

أنا شخصياً لدي كراهية كبيرة لـ Unpin كاسم ، ربما لأنه غالبًا ما يُنظر إليه على أنه ضمني! هذا يعني "حسنًا ، سيتم تثبيت هذا إلى الأبد بمجرد تثبيته في المرة الأولى" ، لذلك لا يمكنني حتى تحسين السلبية المزدوجة.

هذا هو عكس تجربتي تمامًا ، فالتنفيذ اليدوي !Unpin يعني أنك تقوم بتنفيذ بنية مرجعية ذاتية يدويًا باستخدام رمز غير آمن ، وهي حالة استخدام متخصصة للغاية. على النقيض من ذلك ، فإن أي شيء يحتفظ بهيكل يحتمل فكه خلف المؤشر له إشارة إيجابية Unpin . جميع مؤشرات Unpin في std هي قطبية موجبة ، على سبيل المثال.

withoutboats هل يمكنك توفير رابط للمناقشة السابقة حول هذه الأسماء حيث تم بالفعل مناقشة الحجج التي أثيرت هنا؟

إليك موضوع واحد ، على الرغم من أنه تمت مناقشته أيضًا في موضوع RFC ومسألة التتبع https://internals.rust-lang.org/t/naming-pin-anchor-move/6864

(الأنواع الموجودة في سلسلة الرسائل هذه تسمى المرساة والدبوس تسمى الآن Pin<Box<T>> و Pin<&'a mut T> )

هل من المفترض أن يُقرأ Unpin على أنه اختصار لـ Unpinnable؟ غير قابل للفن لأنه لا يمكنك فعلاً إبقاء القيمة مثبتة ، على الرغم من أنها داخل دبوس. (هل هذا فهم صحيح من جانبي؟)

لقد بحثت في بعض المستندات وسلاسل التعليقات ولم أر أي إشارة إلى Unpinnable على وجه التحديد.

لا يُفترض أن يكون Unpin قصيرًا لأي شيء. هناك شيء واحد أعتقد أنه ليس واضحًا لكثير من المستخدمين ، ولكنه صحيح ، هو أن دليل أسلوب المكتبة القياسي هو تفضيل الأفعال كأسماء سمات ، وليس صفات - ومن ثم Send ، وليس Sendable . لم يتم تطبيق هذا باتساق تام ، لكنه القاعدة. Unpin هو مثل "إلغاء التثبيت" ، لأنه من الممكن إزالة هذا النوع من Pin الذي قمت بتثبيته به.

أسماء مثل Move (ليست "قابلة للحركة" تذكر) أقل وضوحًا من Unpin لأنها تشير ضمنًا إلى أن الأمر يتعلق بالقدرة على نقلها على الإطلاق ، بدلاً من ربط السلوك بـ نوع دبوس. يمكنك نقل أنواع !Unpin ، لأنه يمكنك نقل أي Sized في Rust.

الأسماء التي هي عبارات كاملة كما رأيت اقترحت ستكون أحادية للغاية بالنسبة للأمراض المنقولة جنسياً.

قد لا يكون قصيرًا ، لكن هذا هو بالضبط ما قرأته. نظرًا لأن السمات هي أفعال ، يجب عليك تحويلها يدويًا إلى صفة إذا كنت تريد استخدامها لوصف نوع بدلاً من عملية على نوع ؛ std::iter::Iterator بواسطة شيء متكرر ، std::io::Seek يتم تنفيذه بواسطة شيء يمكن البحث عنه ، std::pin::Unpin يتم تنفيذه بواسطة شيء لا يمكن كسبه.

withoutboats هل هناك مشكلة محددة مع بعض الأسماء الأخرى التي لا تحتوي على مشكلة الفعل ، مثل Escape أو EscapePin ؟ أدركت أن هذه المناقشة قد حدثت من قبل ، ولكن من المفترض أن هناك الكثير من العيون على هذا الآن ، لذلك لست متأكدًا من أنها إعادة صياغة زائدة عن الحاجة تمامًا ...

هناك شيء واحد أعتقد أنه صحيح وهو أنه من المؤسف أنه يمكن قراءة Pin و Unpin كزوج (بعض الأنواع هي "pin" وبعضها "unpin") ، عند Pin المفترض أن يكون اسمًا وليس فعلًا . حقيقة أن Pin ليست سمة نأمل أن توضح الأمور. الحجة المؤيدة لـ Pinning منطقية ، لكن هنا نواجه مشكلة طول الاسم. خاصة وأن مستلمي الطريقة سيتعين عليهم تكرار self مرتين ، ينتهي بنا الأمر بالكثير من الأحرف: self: Pinning<&mut Self> . لست مقتنعًا بأن Pinning<P> عبارة عن أربعة أحرف كاملة تستحق الوضوح أكثر من Pin<P> .

tikue فإن مصطلحات "الهروب" مثقلة أكثر بكثير من أعتقد ،

لقد أجرينا هذه المحادثة بالفعل ، وتوصلنا إلى قرار باستخدام Pin و Unpin ، ولم تعد أي من الحجج التي تم طرحها في هذا الموضوع جديدة.

هذا يفركني بطريقة خاطئة - هل تقرير تجربة المجتمع غير مرغوب فيه؟ أنا شخصياً لم أرى مشكلة واضحة مع Unpin حتى بعض التعليقات الأخرى في هذا الموضوع ، بالإضافة إلى التجاور مع Pinned سلبي مزدوج.

لا يقوم Rust بإجراء تحليل الهروب ، لذلك لست متأكدًا من أنني أرى ذلك باعتباره مشكلة حقيقية.

: bell: هذا يدخل الآن فترة التعليق النهائية ، وفقًا للمراجعة أعلاه . :جرس:

ما زلت أرغب في رؤية تحسينات التوثيق كما هو موضح في https://github.com/rust-lang/rust/issues/55766#issuecomment-438316891 قبل هذه الأراضي :)

لقد فتحت https://github.com/rust-lang/rust/pull/55992 لإضافة الوثائق المقترحة أعلاه وإعادة تسمية Pinned إلى PhantomPinned .

أعتقد أن PinnedPhantomPinned ) يشجع على وضع تصور لقيمة "مثبتة" كقيمة لا يمكن نقلها من Pin ، مما يعني أن العديد من القيم في Pin (أولئك الذين تتضمن أنواعهم Unpin ) ليسوا "مثبتين"!

هذا يبدو محيرا. أجد أنه من الأسهل وضع تصور لجميع القيم في Pin كما هو مثبت أثناء وجودهم في Pin ، وما إذا كان التثبيت دائمًا أم لا هو ما كان يُسمى سابقًا Pinned ضوابط Pin* سيمنع الخلط بين مفهومين مختلفين.

PhantomNotUnpin : P

أنا شخصياً لدي كراهية كبيرة لـ Unpin كاسم ، ربما لأنه غالبًا ما يُنظر إليه على أنه ضمني!

شكر! لقد أزعجني أيضًا Unpin لبعض الوقت لم يكن الروبوت قادرًا على تحديد السبب (هيه). الآن أعتقد أنني فهمت: إنه النفي المزدوج.

هذا عكس تجربتي تمامًا ، التنفيذ يدويًا! يعني Unpin أنك تقوم بتنفيذ بنية مرجعية ذاتية يدويًا باستخدام رمز غير آمن ، وهي حالة استخدام متخصصة للغاية. في المقابل ، فإن أي شيء يحافظ على بنية غير مثبتة خلف المؤشر له إشارة إيجابية لـ Unpin. جميع ميزات Unpin في std هي قطبية موجبة ، على سبيل المثال.

لكن الأمر لا يتعلق فقط بالتنفيذ ، بل بالمناقشة أيضًا. impl !Sync نادرًا إلى حد ما (ليس وحده لأنه غير مستقر) ، ولكن الحديث عن أنواع Sync و !Sync أمر شائع جدًا. وبالمثل ، ظهر !Unpin كثيرًا في المناقشات حول هذه الميزة ، على الأقل تلك التي أجريتها.

أنا أيضًا أفضل شيئًا يعبر عن خاصية ما بشكل إيجابي ( MoveFromPin أو نحو ذلك). لست مقتنعًا تمامًا ببيئة العمل ، لأنه على عكس Pin لا يجب على المرء أن يكتب هذه السمة المرتبطة كثيرًا.

لا يقوم Rust بإجراء تحليل الهروب ، لذلك لست متأكدًا من أنني أرى ذلك باعتباره مشكلة حقيقية.

LLVM تفعل ذلك ، لذلك لا يزال تحليل الهروب وثيق الصلة بـ Rust.

طريقة حل ذلك هي اختيار الكلمات التي تعكس معنى Pin / Unpin . على سبيل المثال ، أعد تسمية Unpin إلى Relocate . ثم يصبح !Unpin !Relocate . هذا يبدو أكثر منطقية بالنسبة لي - قرأته على أنه "أوه ، لا يمكن نقل كائنات من هذا النوع". المنافس الآخر هو Movable .

لست متأكدًا من الكلمة المعاكسة التي يمكن أن تحل محل Pin ، أو حتى إذا كنا بحاجة إلى ذلك. لكن يمكنني بالتأكيد أن أتخيل أن المستندات تقول شيئًا كهذا:

يمكن تعديل العنصر المثبت مباشرةً عبر DerefMut إذا وفقط إذا كان من الممكن نقل الكائن في الذاكرة. Relocate سمة تلقائية - يتم إضافتها افتراضيًا. ولكن إذا كانت هناك مؤشرات مباشرة إلى الذاكرة التي تحتوي على قيمك ، فقم بإلغاء الاشتراك في Relocate عن طريق إضافة impl !Relocate على النوع الخاص بك.

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

هذا منطقي أكثر بكثير من Unpin .

لقد فتحت # 55992 لإضافة الوثائق المقترحة أعلاه

هذا يضيف فقط جزءًا مما تم اقتراحه في https://github.com/rust-lang/rust/issues/55766#issuecomment -438316891.

أعجبني اقتراح MoveFromPin . Relocate جيد أيضًا ، ولكن ربما لا يرتبط بـ Pin بما يكفي. يمكن للمرء أن يفهمها مرة أخرى على أنها نوع غير متحرك (وهو ليس كذلك). RelocateFromPin سيكون جيدًا مرة أخرى.

Escape ing هو شيء يرتبط أيضًا على سبيل المثال في Swift بالإغلاق ، وما إذا كان يتم استدعاؤها داخل أو خارج سلسلة الاستدعاء الحالية. هذا يبدو مضللا.

لا أرى أي مشكلات تتعلق بالأسماء الأطول طالما أنها تساعد في الوضوح.

FWIW أرغب في التصويت أيضًا لإعادة تسمية Unpin إلى شيء "إيجابي" مثل Relocate أو MoveFromPin (أو حتى أكثر إسهابًا ولكن ربما أكثر دقة MayMoveFromPin ).

أوافق على أن السالب المزدوج !Unpin أو Unpin كان مربكًا لي تاريخيًا ، وشيء مؤطر بشكل إيجابي "يمكن أن يتحرك هذا على الرغم من كونه داخل Pin " أعتقد من شأنه أن يساعد في تخفيف بعض الارتباك!

FWIW اعتقدت في البداية نفس الشيء حول Unpin ، لكن عندما ذهبت بالفعل لاستخدامه IMO كان من المنطقي - إنه ليس في الحقيقة نفي مزدوج ، لأن العملية التي تبحث عنها هي القدرة على Unpin (خذ شيئًا ما داخل وخارج Pin بحرية) وليس القدرة على إبقاء الأشياء في مكانها. إنه مماثل لـ MoveFromPin ، لكن تمت صياغته بشكل مختلف. أفضل الاسم الذي لا يجعل الناس يعتقدون أنه "ليس Pin " أو شيء من هذا القبيل ، ولكن IMO MoveFromPin والآخرين كثير الكلام جدًا. UndoPin ؟ ( FreePin لحشد haskell؟)

ما زلت أعتقد أن !Unpin يقرأ غريبًا - لقد دربت صوتي الداخلي على التعامل معه مثل "لا تقم بإلغاء تثبيت هذا!" بدلاً من المعتاد "لا ينفذ Unpin " ، لكن الأمر يتطلب بعض الجهد.

ماذا عن !Pluck ؟

تضمين التغريدة

بدلاً من الخيار المعتاد "لا ينفذ Unpin"

لقد ذكرت هذا في تعليقي السابق ، لكنني أعتقد أن هذه طريقة جيدة لقولها: Unpin هي عملية إدخالها وإخراجها من Pin<C<_>> . الأشياء التي لا تنفذ Unpin لا توفر هذه القدرة.

cramertj أحب تمامًا UndoPin

cramertj أوافق على أنني لست معجبًا كبيرًا بالبدائل المقترحة حتى الآن ، لكنني شخصياً أفضل استخدام الكلمات MoveFromPin على Unpin . إنها نقطة جيدة أنها ليست سلبية مزدوجة ، ولكن عند قراءتها (كشخص لم يعمل معها كثيرًا حتى الآن) ، فإنها تستمر في تعثلي بأنها سلبية مزدوجة. ما زلت أحاول قراءة البادئة "Un" على أنها سلبية ...

أشعر بالفضول ، لكن cramertj أو غيره تشعر أن هناك طريقة جيدة Unpin المربوط بشكل مريح؟ هل هو نادر للغاية؟ هل هو شائع للغاية؟ شائع بما يكفي ليكون مؤلمًا إذا كان من المؤلم الكتابة؟

للحصول على اسم قصير ولطيف ، فأنا شخصياً أحب فكرة Relocate ، ولكن بالنسبة لاسم أطول وألفظ ولكن لا بأس به لأنك لا تكتبه بقدر ما أحب MoveFromPin . أنا شخصياً أشعر أنه بغض النظر عن بيئة العمل لكتابة الاسم ، فإن كلاهما أفضل من Unpin

أنا فضولي ، لكن cramertj أو الآخرين هل تشعر أن هناك معالجة جيدة لمدى ظهور Unpin بشكل مريح؟ هل هو نادر للغاية؟ هل هو شائع للغاية؟ شائع بما يكفي ليكون مؤلمًا إذا كان من المؤلم الكتابة؟

في تجربتي ، هناك حالتان يظهر فيهما Unpin في كود المستخدم:

  1. تظهر حدود Unpin لأنك تحتاج بالفعل إلى التحرك في المستقبل أثناء قيامك باستطلاع الرأي (على سبيل المثال ، أشياء مثل بعض واجهات برمجة التطبيقات المحددة).
  2. بشكل أكثر شيوعًا ، إذا كان مستقبلك عامًا فقط على شيء آخر غير المستقبل ، فأنت تريد عادةً إضافة تنفيذ غير مشروط Unpin ، لأنه لا يهم إذا كانت هذه الأنواع الأخرى Unpin لأنك لم تفعل ذلك أبدًا مشروع دبوس لهم.

مثال على الحالة الثانية هو إذا كان لديك نوع من نوع المخزن المؤقت الذي تريده بشكل عام (على سبيل المثال T: AsRef<[u8]> ). لا تحتاج إلى تثبيته لإخراج الشريحة منه ، لذلك لا تهتم إذا كان يستخدم Unpin أم لا ، لذلك تريد فقط أن تقول إن النوع الخاص بك ينفذ دون قيد أو شرط Unpin حتى تتمكن من التنفيذ Future تجاهل التثبيت.

Unpin الشائع جدًا رؤيته كالتقييد-- select! و StreamExt::next وجميع أدوات الدمج الأخرى تتطلب جميع الأنواع التي تعمل عليها أن تكون Unpin .

withoutboats أنا أشعر بالفضول بشأن impl Unpin شيء يجب على الناس تذكره لتنفيذه كثيرًا؟ على غرار الطريقة التي ينسى بها مؤلفو المكتبات اليوم استخدام #[derive(Debug)] أو impl std::error::Error لأنواعهم المخصصة ، مما يجعل استخدام هذه المكتبات أكثر صعوبة؟

Unpin هو سمة تلقائية. المرة الوحيدة التي سيكون لديك فيها نوع لا يطبق إلغاء التثبيت هو عندما يخرج هذا النوع صراحةً منه. (أو يحتوي على حقل يختار إلغاء التثبيت).

أنا أفهم أن هذا هو الحال. وافترضت أن هذه ستكون الحالة الأكثر شيوعًا إلى حد بعيد ، ولهذا السبب فوجئت بذكرwithoutboats حتى النقطة الثانية. يقترح لي أنه قد يكون أكثر شيوعًا مما كنت أعتقد في الأصل (على الرغم من أنه ربما يكون ذلك فقط عند تنفيذ العقود المستقبلية الخاصة بك) ، لذلك أنا فضولي بشأن تكرار هذه الأنواع من حالات الاستخدام :)

alexcrichton أنا فضولي ، لكن cramertj أو الآخرين هل تشعر أن هناك معالجة جيدة لمدى ظهور Unpin المريح؟ هل هو نادر للغاية؟ هل هو شائع للغاية؟ شائع بما يكفي ليكون مؤلمًا إذا كان من المؤلم الكتابة؟

لقد كتبت منشورًا طويلاً عن تجربتي في نقل الكود الخاص بي إلى Futures 0.3 (والذي يستخدم Pin ). لست بحاجة لقراءته ، الملخص هو:

في معظم الأوقات ، لا داعي للقلق بشأن Unpin على الإطلاق ، لأن Unpin يتم تنفيذه تلقائيًا لجميع الأنواع تقريبًا.

لذا فإن المرة الوحيدة التي يجب أن تقلق فيها بشأن Unpin هي:

  1. لديك نوع عام على الأنواع الأخرى (مثل struct Foo<A> ).

  2. وتريد تنفيذ API تعلق (على سبيل المثال Future / Stream / Signal ) لهذا النوع.

في هذه الحالة تحتاج إلى استخدام هذا:

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

أو هذا:

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

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

عادة ما يكون هذا هو الموقف الوحيد الذي يحتاج فيه Unpin . كما ترى ، يعني هذا عادةً الحاجة إلى استخدام Unpin ~ مرتين لكل نوع.

في حالة عدم الدمج ، أو في حالة الأنواع التي لا تطبق Future / Stream / Signal ، لست بحاجة إلى استخدام Unpin على الإطلاق.

لذلك أود أن أقول أن Unpin يظهر نادرًا جدًا ، ولا يظهر إلا في حالة إنشاء وحدات دمج Future / Stream / Signal .

لذلك أنا أؤيد بشدة اسم مثل MoveFromPin . التثبيت هو ميزة متخصصة لا يحتاج معظم الناس للتعامل معها أبدًا ، لذلك لا ينبغي أن نبالغ في تحسين طول الاسم.

أعتقد أن الفوائد المعرفية (تجنب النفي المزدوج) أهم بكثير من حفظ بعض الشخصيات في مواقف نادرة.

خاصة وأن التثبيت صعب بالفعل بما يكفي لفهمه! لذلك دعونا لا نجعل الأمر أكثر صعوبة بلا داع.

jonhoo ، هل نعتقد أن impl Unpin هو شيء يجب على الناس تذكره لتنفيذه كثيرًا؟ على غرار الطريقة التي ينسى بها مؤلفو المكتبات اليوم أن ينسوا #[derive(Debug)] أو impl std::error::Error لأنواعهم المخصصة ، مما يجعل استخدام هذه المكتبات أكثر صعوبة؟

لا أعتقد أنه من الممكن نسيان impl Unpin ، لأنه إذا نسي المؤلف ، فسوف يحصل على خطأ في المترجم ، مما يمنع الصندوق من النشر في المقام الأول. لذلك فهي ليست مثل #[derive(Debug)] على الإطلاق.

إن الموقف الذي يتحدث عنه withoutboats مخصص فقط للأشخاص الذين Future / Stream / Signal ، لا يؤثر ذلك على أي شخص آخر (على وجه الخصوص ، لا يؤثر المستخدمين المصب للمكتبة).

(أعتقد أن النفي المزدوج هو جزء منه ، وربما يكون النفي أكثر من الضرورة القصوى كذلك ، لكنني أشعر أنها ليست القصة بأكملها (محاولة الاستبطان هنا) ... "Unpin" قليل ، مجازي ، غير مباشر ، يكون منطقيًا عند شرحه ، وبما أن "التثبيت" نفسه هو بالفعل استعارة ، فليس من الواضح لماذا يواجه عقلي مشكلة في أخذ المزيد من هذه الاستعارة ، ولكن ، مع ذلك ، يجد عقلي معنى "فك التثبيت" لسبب ما غامض ويصعب الإمساك به بحزم.)

أعتقد أنك على حق cramertj ، فهذا ليس في الواقع إنكارًا مزدوجًا بالمعنى المعتاد ، لكن مثل alexcrichton و glaebhoerl أستمر في التعثر به. "Un-" كبادئة لها شعور نفي للغاية ("غير آمن" ، "غير مُنفَّذ" وما إلى ذلك هو كيف أواجه هذه البادئة عادةً) ، وهو ينفي التثبيت هنا ، ولو كفعل فقط.

withoutboats أنا أشعر بالفضول بشأن

بالطبع لا! إذا كان المستخدم يطبق يدويًا Future وهو عام على غير المستقبل ، فمن المحتمل أن يكون قادرًا على تغيير الحالة في التنفيذ المستقبلي دون كتابة رمز غير آمن - أي للتعامل مع Pin<&mut Self> كـ &mut self . سيحصلون على أخطاء تشير إلى أن MyFuture<T: AsRef<[u8]>> لا يطبق Unpin . أفضل حل لهذه المشكلة هو تنفيذ Unpin . لكن التأثير الوحيد لذلك هو على المستخدم الذي يحاول تنفيذ Future ، ومن المستحيل عليهم نسيانه لأن الكود الخاص بهم لن يتم تجميعه.

الموقف الذي يتحدث عنه withoutboats مخصص فقط للأشخاص الذين يطبقون تركيبات Future / Stream / Signal ، ولا يؤثر على أي شخص آخر (على وجه الخصوص ، لا يؤثر على مستخدمي المكتبة في نهاية المطاف)

أنا أتحدث بشكل خاص عن العقود الآجلة اليدوية العامة غير المجمعة ، والتي يجب أن تحتوي فقط على أدوات شاملة بقيمة Unpin حتى لو لم تكن الأدوية الخاصة بهم Unpin .

لقد أنشأت مخططًا انسيابيًا للسؤال "ماذا أفعل بشأن التثبيت عندما أقوم بتنفيذ مستقبل / تدفق يدوي؟"

pinning-flowchart

لركوب الدراجات أكثر قليلاً ، خطرت اليوم على الغداء LeavePin . وهي تحمل نفس نغمة escape بدون الدلالات الضمنية المضللة.

هل هناك تفاعلات مثيرة للاهتمام بين ضمني التخصص والدبابيس ، كما هو الحال مع العمر؟

تحدث السلسلة الفرعية "specializ" في تتبع مناقشة المشكلة قليلاً ، لكنها ليست قاطعة. يجب أن يذكر Pin RFC أو التخصص هذا التفاعل صراحةً ، إما على أنه "تم التحقق من أنه على ما يرام" أو "يلزم إجراء مزيد من البحث للحكم على أنه آمن"

vi ليس فقط لا يوجد تفاعل سلامة ، وليس من الممكن أن يكون هناك تفاعل سلامة. يتم تعريف واجهات برمجة تطبيقات الدبوس بشكل صارم في المكتبة القياسية ولا تتضمن ميزات لغة جديدة ، يمكن للمستخدم تحديدها بنفس السهولة في مكتبات الطرف الثالث. إذا كانت ميزة اللغة غير سليمة في مواجهة رمز المكتبة هذا ، فهي فترة غير سليمة ، لأن أي مستخدم يمكنه كتابة رمز المكتبة هذا اليوم وسيتم تجميعه بشكل جيد.

إذا كانت ميزة اللغة غير سليمة في مواجهة رمز المكتبة الموجود ، فهذه فترة غير سليمة ، لأن أي مستخدم يمكنه كتابة رمز المكتبة هذا اليوم وسيتم تجميعه بشكل جيد.

لا يعني ذلك أنه يجب أن يكون له أي تأثير على pin ... لكنني لا أعتقد أن الأمر بهذه البساطة.

إذا كانت إحدى ميزات المكتبة ، عند استخدام unsafe ، تستخدم تركيبات اللغة التي لم يتم تحديد سلوكها بعد (على سبيل المثال ، &packed.field as *const _ ، أو وضع افتراضات مختلفة حول ABI) ثم إذا تغيرت اللغة الإضافية تبطل الافتراضات من تلك المكتبات إذن أعتقد أن المكتبات غير سليمة وليست اللغة تتغير. من ناحية أخرى ، إذا أدت تغييرات اللغة إلى جعل السلوك المحدد غير سليم ، فهذا خطأ في تغيير اللغة. وبالتالي ، فإن تجميع الغرامة ليس شرطًا كافيًا لسلامة المكتبة في مواجهة التغييرات غير الآمنة واللغوية.

+1 إلى MoveFromPin أو ما شابه

إذا طرحت السؤال "متى يجب إلغاء تطبيق Unpin لنوع خاص بي؟" ، فستكون الإجابة أكثر وضوحًا إذا سألت بدلاً من ذلك "متى يجب عدم تطبيق MoveFromPin لنوع خاص بي؟"

نفس الشيء مع "هل يجب أن أضيف Unpin كصفة ملزمة هنا؟" مقابل "هل يجب علي إضافة MoveFromPin كصفة ملزمة هنا؟"

التثبيت ليس كذلك!

عذرًا إذا تم ذكر ذلك في مكان ما ، لكنني قمت فقط بتخطي الكم الهائل من المناقشات التي دارت حول Pin هنا ، في قضية التنفيذ ، وفي قضية RFC.

هل الصدأ سيكون يوما ما! يمكنني بالتأكيد رؤية حالات استخدام لمثل هذا الشيء (حسنًا ، لقد جئت أبحث عن Pin لأنني كنت أبحث عن طريقة لعدم إطلاق النار على قدمي بأنواع لا يمكن نقلها). إذا كان الجواب نعم ، فكيف سيتفاعل ذلك مع Pin؟ هل وجود Pin سيجعل الأمر أصعب مما هو عليه بالفعل لإضافة! Move؟

اكتملت الآن فترة التعليق النهائية ، مع إمكانية الدمج ، وفقًا للمراجعة أعلاه .

يجب أن يكون هناك قلق لم يتم حله حول تسمية Unpin.

كما أشار RalfJung ، يضيف # 55992 أيضًا قدرًا صغيرًا من الوثائق الإضافية المطلوبة في https://github.com/rust-lang/rust/issues/55766#issuecomment -438316891 وأماكن أخرى. لا أعرف أن هذا سبب لعدم الدمج حتى الآن.

لماذا تأخذ طريقة Drop () الخاصة بي الآن & mut self بدلاً من Pin.

حسنًا ، drop () قديم - إنه موجود منذ Rust 1.0 - لذلك لا يمكننا تغييره. نود أن نجعل الأمر يأخذ Pin <& mut Self> ، ومن ثم يمكن لأنواع Unpin الحصول على & mut كما يفعلون الآن ، ولكن هذا تغيير غير متوافق مع الإصدارات السابقة.

كنت أتساءل عما إذا كان من الممكن تنفيذ هذا التغيير بطريقة متوافقة مع الإصدارات السابقة. AIUI حتى نضيف Unpin (ويمكن للأشخاص تحديد !Unpin ) جميع الأنواع تنفذ Unpin . حتى نتمكن من إضافة سمة:

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

ثم ضمّن هذه السمة لجميع أنواع Unpin ، والتي حتى يتمكن الأشخاص من إلغاء الاشتراك هي جميع الأنواع. شيء مثل:

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

ثم لدينا المترجم أدخل المكالمات إلى DropPinned::drop بدلاً من Drop::drop . في الأساس ، تصبح السمة DropPinned العنصر lang بدلاً من Drop . AFAICS سيكون هذا متوافقًا مع الإصدارات السابقة إذا وفقط إذا تم تقديم هذه الآلية في نفس الوقت مثل Unpin .

يجب أن يكون هناك قلق لم يتم حله حول تسمية Unpin.

tikue لا يقدم عضو فريق libs شكوى مع rfcbot قبل أو أثناء FCP ، ولا أعتقد أن أيًا من الحجج حول Unpin كانت جديدة أو جديدة على هذا الموضوع ، لذلك عادةً ما تأخذ عمليتنا الحالية في الاعتبار التسمية التي سيتم الانتهاء منها. من الواضح أنه إذا كان لدى شخص ما مخاوف ، فيجب عليه التحدث ، ولكن الهدف من وجود مربعات اختيار للفريق يتبعها FCP هو التأكد من أن الجميع مرتاحون في تثبيت API كما هو مقترح.

cramertj أنا مرتبك قليلاً. وتحدث العديد من الناس. عندما سألت عن مراجع حول الأماكن الأخرى التي أثيرت فيها الحجج حول تسمية Unpin وتم حلها ، أشير إلى https://internals.rust-lang.org/t/naming-pin-anchor- move / 6864 ، والتي بقدر ما أستطيع أن أرى الناس أيضًا يشكون من تسمية Unpin ، ولا توجد حجة مضادة حقيقية. لا يحتوي RFC الأصلي في https://github.com/rust-lang/rfcs/pull/2349 أيضًا على مبرر كبير لسبب سوء البدائل المقترحة لـ Unpin . حتى في هذا الموضوع ، يبدو أن الحجج المضادة الوحيدة التي تظهر حقًا هي "إنها أقصر" و "صحيحة تقنيًا". هل أنت قادر على الإشارة إلى مناقشة ملموسة حيث تتم مناقشة الأسماء البديلة التي يسهل فهمها (مثل MoveFromPin ) ورفضها؟

لقد شرحت في التعليقات السابقة لماذا أعتقد أنه تم طرح وجهات نظر جديدة في هذا الموضوع. لقد كنت أتابع مناقشات API عن كثب إلى حد ما منذ البداية ولا أتذكر أبدًا رؤية المشكلة السلبية المزدوجة التي ظهرت قبل هذا الموضوع.

tikue لقد طرحت ورأيت المشكلة المزدوجة السلبية التي تم طرحها عدة مرات ، وتم طرح التسمية الدقيقة لـ Unpin كمشكلة عدة مرات وتم حلها باستمرار لصالح Unpin . كما قلت من قبل، اذا كان شخص ما على فريق يبس يريد تسجيل (الراحل) اعتراض ثم أنا الاستجابة غرامة على ذلك، لكنهم جميعا وقع على الاقتراح الاستقرار أعلاه والتي بوضوح لا يتضمن تسمية Unpin كسؤال لم يتم حله: لقد ناقشنا البدائل ، وكان FCP هذا هو عملية اتخاذ قرار بأننا مستعدين لتحقيق الاستقرار في القرارات التي تم اتخاذها ، بما في ذلك الاسم Unpin .

cramertj هل يمكنك من فضلك توفير رابط إلى مكان حدوث هذه المناقشة؟ أنا لا أشك فيك ، أود فقط أن أرى الحجج المؤيدة لـ Unpin ، لأنني لا أعتقد أنه تم تقديمها هنا. كما ذكرنا سابقًا ، المراجع التي تلقيتها حتى الآن لا تقدم أي حل بشأن تسمية Unpin .

cramertj +1 لسؤال @ jonhoo . إذا كانت هناك مناقشات أجراها فريق libs فيما بينهم ولم يتم تسجيلها في القنوات الرسمية ، أعتقد أنه يجب تكرار التوجه الرئيسي لهذه المناقشات هنا. أعتقد أن هناك حتى قاعدة رسمية مفادها أنه لا يمكن اتخاذ قرارات RFC إلا بناءً على الحجج المعلنة؟

أعتقد أن هناك حتى قاعدة رسمية مفادها أنه لا يمكن اتخاذ قرارات RFC إلا بناءً على الحجج المعلنة؟

نعم ، هذا صحيح - وللتسجيل ، أنا لست عضوًا في فريق libs وبالتالي لم أحضر أي مناقشات لفريق libs فقط. بالنظر إلى سلسلة RFC ومسألة التعقب Pin ، كانت هناك عدة مرات حيث تم طرح اسم Unpin . أنا لا أرى أي شخص يقول على وجه التحديد عبارة "النفي المزدوج"، لكنني بالتأكيد تذكر " !Unpin هو النفي المزدوج" التي جلبت من قبل، بالإضافة إلى حكم API العامة من الصفات التسمية ما استطعتم تفعل معهم ، بدلاً من ما لا يمكنك (كما أشرت أعلاه ، أعتقد أن Unpin يتبع في الواقع هاتين القاعدتين ، على الرغم من إدراك ذلك يتطلب سماع "Unpin" كفعل بدلاً من سماعه كصفة "not-pin" ، وهو أمر ليس بديهيًا للأشخاص).

wmanley هذا لا يعمل ، على سبيل المثال impl<T> Drop for Vec<T> قد ينكسر لأنه ليس لدينا Vec<T>: Unpin . أيضًا ، تم تقديم مقترحات على طول هذا الخط من قبل ، حتى في هذا الموضوع . يرجى قراءة المناقشات قبل الرد. أعلم أن هذا يتطلب الكثير جدًا ، لكنه الطريقة الوحيدة لتجنب شرح نفس المشكلات مرارًا وتكرارًا.

أعتقد أن هناك حتى قاعدة رسمية مفادها أنه لا يمكن اتخاذ قرارات RFC إلا بناءً على الحجج المعلنة؟

يُعرف هذا بشكل غير رسمي بقاعدة "لا يوجد سبب منطقي جديد" .

لست متأكدًا من مكان نشر هذا ، ولكن هل يمكن لشخص ما إلقاء نظرة على https://github.com/rust-lang/rust/issues/56256 ؟

بالنسبة إلى # 56256 ، لم يتم إدراج impl<T> From<Box<T>> for Pin<Box<T>> في OP باعتباره مستقرًا ، ولكنه سيصبح مستقرًا ضمنيًا بمجرد Pin . هل هناك أي تطبيقات أخرى للسمات ليست تافهة ويجب النظر إليها من أجل الاستقرار؟ (يبدو أن مسح جميع المستندات الأخرى يبدو وكأنه تفويض تافه لتطبيقات المؤشر المغلف بالنسبة لي).

تحدثنا عن هذا الموضوع في فريق libs اليوم. أظهرت الأسابيع الأخيرة من المناقشة أنه لا تزال هناك بعض الأشياء التي يجب معالجتها أولاً ، خاصةً فيما يتعلق بتسمية Unpin .

لذلك لن نمضي قدمًا في تثبيت هذا في الوقت الحالي (على الرغم من FCP).

سيكون موضع تقدير كبير إذا تمكن شخص ما من جمع الأفكار في هذا الموضوع وإعداد اقتراح مستقل لتحسين حالة التسمية.

تضمين التغريدة

سيكون موضع تقدير كبير إذا تمكن شخص ما من جمع الأفكار في هذا الموضوع وإعداد اقتراح مستقل لتحسين حالة التسمية.

هل هذا يعني أن فريق libs غير راغب في تثبيت واجهات برمجة التطبيقات الحالية كما هي؟ أنا شخصياً لا أعتقد أن أي شخص قد توصل إلى اسم أفضل من المجموعة الحالية من الأسماء كما تم تنفيذها ، ولذلك لا يمكنني تقديم مثل هذا الاقتراح ، لكني أهتم كثيرًا برؤية واجهات برمجة التطبيقات هذه مستقرة ، لذلك إذا كان لدى شخص ما من فريق libs اسم يفضلونه ، فحينئذٍ:

قام Bikesh بتضمين هذا مع مجموعة من زملاء العمل و anp اقترح DePin ، وهو ما أحبه كثيرًا ، لأنه يزيل دلالة "not pin" لـ Unpin ويؤكد أنه يتحدث عن نوع والتي يمكن أن تكون de- Pin 'd.

@ Kimundi ، هل يمكنك أنت أو أي شخص من فريق libs تسجيل "قلق fcp" الصريح لإخراج هذا من FCP ووضع بشكل أكثر وضوحًا ما هو المقصود بـ "بعض الأشياء التي يجب معالجتها"؟

rfcbot قلق تسمية

لست متأكدًا مما إذا كان هذا يعمل حقًا بمجرد إدخال FCP ، ولكن أود وضع مخاوف رسمية بشأن الحظر على تسمية السمة Unpin . يبدو أن السمة Unpin مهمة جدًا لواجهة برمجة التطبيقات ، و "السلبية المزدوجة" (كما تمت مناقشته أعلاه) تدفعني إلى الدوران في كل مرة أقرأها.

كانت هناك مجموعة كاملة من التعليقات حول أسماء مختلفة ، لكن لسوء الحظ لم أشعر بسعادة غامرة تجاه أي منها حتى الآن. "المفضلة" الخاصة بي لا تزال على غرار MoveFromPin أو Relocate (يا إلهي ، هناك الكثير من التعليقات هنا وليس لدي أي فكرة عن كيفية مراجعة هذا).

أنا شخصياً موافق على تسمية Pin نفسها بالإضافة إلى Pinned لـ ZST الذي لا يطبق السمة Unpin .

أتفق تمامًا مع alexcrichton على أن تسمية Unpin هي نقطة الخلاف الكبرى هنا. لا أعتقد أن هناك أي مخاوف فنية بقدر ما أستطيع رؤيتها حول الميزة المقترحة نفسها (على الرغم من وجود _ يوجد _ الكثير من التعليقات ، لذلك ربما فاتني شيء ما).

ما زلت أعتقد أن Pinned هو اسم غريب لـ ZST ، لأن الشيء الذي يحتوي على Pinned غير مثبت بالفعل .. إنه ليس Unpin . PhantomPinned (حيث تمت إعادة تسميته في # 55992) له نفس المشكلة من حيث أنه يشير إلى Pin ، عندما يكون ZST هو _really_ حوالي Unpin .

ما زلت أعتقد أيضًا أن المستندات بحاجة إلى مزيد من العمل نظرًا لدقة هذه الميزة ، ولكن ربما لا يعتبر ذلك مانعًا.

أيضًا ، @ Kimundi ، يسعدني أن أرى أن فريق libs على استعداد لمنح هذا مزيدًا من الوقت لتسوية. قد يبدو الأمر أشبه بتساقط دراجات غير ضروري ، لكنني (وآخرين أيضًا على ما يبدو) أعتقد أنه من المهم جدًا تحسين قابلية هذه الميزة للتعلم :)

تم الاتفاق مع jonhoo على أن Pinned لا يزال يشعر بالغرابة ، و PhantomPinned ليس أفضل (لم يتم تثبيته بأي شكل من الأشكال ، ولا حتى بطريقة وهمية). أعتقد أنه إذا وجدنا اسمًا جيدًا لـ Unpin ، فسيتم إعادة تسمية Not{NewNameForUnpin} Pinned بشكل طبيعي لإعادة تسميته Not{NewNameForUnpin} .

لا أعتقد حقًا أننا بحاجة إلى قضاء المزيد من الوقت في مناقشة PhantomPinned - لن يظهر هذا النوع أبدًا للمستخدمين النهائيين. PhantomNotUnpin / PhantomNotDePin / PhantomNotMoveFromPin / وما إلى ذلك إلى جعله أكثر أو أقل شيوعًا أو جعل واجهة برمجة التطبيقات أكثر أو أقل وضوحًا للمستخدمين الذين يشعرون بالفعل بالراحة الكافية مع API للتوصل إلى استخدام شرعي لـ PhantomPinned .

مجرد فكرة سريعة: السمة Move و ZST Anchor .

كل نوع قادر على Move ، ما لم يكن يحتوي على Anchor الذي يجعله يلتزم بـ Pin .
أحب الطريقة التي يكون بها Anchor: !Move بشكل حدسي الكثير من المعنى.

لا أقترح قضاء الوقت على وجه التحديد على PhantomPinned ، لكنني أعتقد أنه سيكون جهدًا ضئيلًا للحفاظ على عقل متفتح ، لأنه من المحتمل أن كل ما يتم الحصول عليه مقابل Unpin سيعمل وكذلك مقابل PhantomPinned .

لقد غطينا Move وشرحنا سبب كونه غير مناسب مرات عديدة. جميع الأنواع قابلة للحركة حتى يتم تثبيتها. وبالمثل ، تم اقتراح Anchor سابقًا ولكن ليس من الواضح على الإطلاق من الاسم أنه يُستخدم لإلغاء الاشتراك في Unpin ing / Move ing.

stjepang أعتقد أن Move قد تم إهماله منذ فترة لأن شيئًا ما !Unpin لا يمنعه في الواقع من النقل. فقط إذا كان النوع أقل من Pin ، ولم يكن Unpin ، فأنت "ملزم تعاقديًا" بعدم نقله.

في التعليق الأصلي قال withoutboats :

يعدل الغلاف Pin المؤشر إلى "تثبيت" الذاكرة التي يشير إليها في مكانها

أعتقد أنه من الغريب أن تقوم الأنواع بتنفيذ Unpin لأن القيم ليست "مثبتة" - الذاكرة كذلك. ومع ذلك ، فمن المنطقي التحدث عن قيم "آمنة للتنقل". ماذا لو أعدنا تسمية Unpin إلى MoveSafe ؟

ضع في اعتبارك السمة UnwindSafe . إنها مجرد سمة علامة "تلميح" وهي آمنة للتنفيذ. إذا سمحت لقيمة !UnwindSafe بعبور حد catch_unwind (مع AssertUnwindSafe ) ، فسوف "تكسرها" بإبطال ثوابتها.

وبالمثل ، إذا كانت لديك قيمة !Unpin / !MoveSafe ، فلا يزال من الممكن نقلها (بالطبع) ، لكنك ستكسرها بإبطال مراجعها الذاتية. يبدو المفهوم مشابهًا.

السمة Unpin تعني فقط MoveSafe . يبدو لي أن الأمر لا يتعلق بالقيم التي يمكن نقلها من الذاكرة خلف Pin . بدلاً من ذلك ، يتعلق الأمر بالقيم التي لن "تنكسر" عند نقلها.

يواجه MoveSafe نفس المشكلة مثل Move - يمكن نقل جميع القيم بأي نوع بأمان. يصبح من المستحيل نقل قيمة بعد تثبيتها فقط.

يواجه MoveSafe نفس المشكلة مثل Move - يمكن نقل جميع القيم بأي نوع بأمان.

صحيح ، ولكن معنى مختلف لكلمة "آمن" ، تمامًا كما هو الحال في UnwindSafe . على أي حال ، سأكون بخير مع Relocate أو أي شيء من هذا القبيل.

للتلخيص ، أشعر أن اسم السمة يجب ألا يكون DePin أو Unpin أو أي شيء به "pin" في اسمه. بالنسبة لي ، هذا هو المصدر الرئيسي للارتباك. السمة ليست في الحقيقة "فتحة هروب" من أغلال Pin - تقول السمة أن القيمة لن تُبطل عند نقلها.

أرى فقط Pin و Unpin أشياء منفصلة تمامًا. :)

أشعر بالعكس تمامًا ؛). تكون السمة ذات معنى فقط فيما يتعلق بـ Pin ، وهو النوع الوحيد الذي لدينا والذي يعبر بشكل هادف عن قيود على قابلية نقل القيمة الأساسية. بدون Pin ، فإن Unpin لا معنى له تمامًا.

أحب التفكير في التثبيت على أنه وضع شيء ما على لوح الدبوس. إذا قمت بإزالة دبوس كائن مثبت على اللوحة ، فيمكنك تحريك الكائن. إزالة الدبوس هي إزالة التثبيت.
يعجبني الاسم Unpin .

أستطيع أيضًا أن أرى كيف! Unpin هو نفي مزدوج ، ويمكن أن يسبب الارتباك. ومع ذلك ، أتساءل كم مرة تحتاج إلى كتابة !Unpin .

اسم آخر يمكن أن أضعه في Unpin هو Detach . بالعودة إلى استعارة لوحة الدبوس ، لن تقوم بفك الدبوس ، لكنك تفصل الدبوس عن الكائن الخاص به.

أعتقد أنني معجب حقًا DePin ! إنها المفضلة حتى الآن - إنها موجزة ، ومن الواضح أنها فعل وليست صفة ، ويبدو أيضًا !DePin واضحًا جدًا ("لا يمكن فك التثبيت").

أعتقد أنه من الغريب أن تقوم الأنواع بتنفيذ Unpin لأن القيم ليست "مثبتة" - الذاكرة.

القيمة مثبتة في الذاكرة. لكن القيمة مهمة للغاية هنا أيضًا. يتعلق تثبيت الذاكرة ، بالنسبة لي ، بالتأكد من أنها تظل قابلة للإلغاء أو ما شابه ، ولكن لا يتم انتهاكها بواسطة mem::swap . يتعلق تثبيت قيمة في الذاكرة بعدم نقل تلك القيمة المثبتة إلى أي مكان آخر ، وهو بالضبط ما يدور حوله Pin .

أستطيع أيضًا أن أرى كيف! Unpin هو نفي مزدوج ، ويمكن أن يسبب الارتباك. ومع ذلك ، أتساءل كم مرة تحتاج إلى الكتابة!

أسمعك عندما تقول أنك لا تجد الاسم محيرًا. لقد وجدت أنا والعديد من الآخرين في هذا الموضوع مشوشين من التسمية.

ليس لدي الكود في متناول اليد ، لكن في المرة الأولى التي حاولت فيها استخدام العقود الآجلة ، أردت وظيفة لإرجاع impl Future<Output=T> . لا أستطيع تذكر ما حدث ، لكنني حصلت على الفور على خطأ في المترجم يشكو من T و Unpin. كان السؤال الذي كنت بحاجة إلى إجابة له هو "هل من الآمن تقييد T حتى يتم إلغاء التثبيت فقط". وقد قادني ذلك إلى التحديق في الهاوية لمدة ساعتين مروعتين.

"أوه ، حسنًا ، إذا كان هذا هو ما يعنيه Pin. إذن Unpin يعني .. Box؟ لماذا هذه سمة؟"

"انتظر ، impl !Unpin ؟ لماذا هذا ليس impl Pin ؟"

"صحيح ، Pin و Unpin ... ليست متضادات. إنها أشياء مختلفة تمامًا. انتظر ، فماذا يعني Unpin مرة أخرى؟ لماذا يسمى ذلك؟"

"ماذا يعني !Unpin على الأرض؟ لا ... الآخر ، وليس الشيء المعلق؟ Hrrrgh"

لا تزال الطريقة الوحيدة المنطقية في رأسي هي استبدال "unpin" بـ "relocatable". "الكتابة لا يمكن إعادة تحديد موضعها في الذاكرة" لها معنى كامل. ومع ذلك ، حتى مع معرفة ما يفعله Pin ، فإن عبارة "الكتابة لا تؤدي إلى إلغاء

إعادة تسمية Unpin إلى Relocatable (أو Relocate ) تحصل على تصويتي 🗳. لكنني أجد أيًا من الاقتراحات الأخرى أفضل من Unpin.

تكون السمة ذات معنى فقط فيما يتعلق بـ Pin ، وهو النوع الوحيد الذي لدينا والذي يعبر بشكل هادف عن قيود على قابلية نقل القيمة الأساسية. بدون Pin ، فإن Unpin لا معنى له تمامًا.

لوضع نقطة على هذا - الضمانات حول الدبوس تدور تمامًا حول سلوكيات معينة ، وليس أنواعًا . على سبيل المثال ، يمكن لوظيفة المولد التي تنتج () تنفيذ FnOnce بشكل بسيط عن طريق الاستئناف بشكل متكرر. على الرغم من أن هذا النوع قد لا يطبق Unpin - نظرًا لأن حالات الإنتاجية الخاصة به يمكن أن تكون مرجعية ذاتية ، فإن واجهته FnOnce (التي تتحرك بنفسها) آمنة تمامًا لأنه لم يتم تثبيتها بعد عند FnOnce هو ، وهو أمر ضروري لجعله في حالة مرجعية ذاتية. Unpin على وجه التحديد بأنواع السلوكيات المؤكدة على أنها آمنة بمجرد تثبيت النوع (أي تحريكه) ، وليس حول بعض الخصائص الجوهرية للنوع.

ومن المفارقات أنني أتيت للتو إلى هنا للتعليق على أنه بينما تمت مناقشة التسمية Unpin بالتأكيد في الماضي ، فإن الجدل حولها الذي أتذكر أنني شاهدته كان عندما اخترنا استبدال Move بـ Unpin ، والذي كنت سأقوله ، هو تحسن لا لبس فيه . وغالبًا ما يدرك المرء ذلك لاحقًا ، في حين أن التصميم الحالي يمثل تحسينًا واضحًا لما جاء من قبل ، إلا أنه لا يزال هناك بعض المساحة المتبقية لمزيد من التحسين. وهو الاتجاه الذي كنت أتيت منه في هذا.

يتعلق Unpin على وجه التحديد بأنواع السلوكيات التي يتم التأكيد على أنها آمنة بمجرد تثبيت النوع (أي تحريكه) ، وليس حول بعض الخصائص الجوهرية للنوع.

السلوك عند التثبيت هو خاصية جوهرية للنوع ، تمامًا مثل السلوك / الثابت عند مشاركته. لقد تناولت هذا بتفاصيل أكثر بكثير في منشور المدونة هذا .

RalfJung نحن نتحدث بعد بعضنا البعض. أرى الكثير من الالتباس بأن الأنواع المرجعية الذاتية "لا يمكن نقلها" - هذا ليس دقيقًا ، لديهم حالات معينة يمكنهم الدخول فيها ولا يمكن نقلهم خلالها ، ولكن أثناء وجودهم في حالات أخرى ، فهي آمنة تمامًا لنقلهم (وتعتمد واجهات برمجة التطبيقات الخاصة بنا على القدرة على نقلهم ، على سبيل المثال لتطبيق المجمعات عليهم أو نقلهم إلى Pin<Box<>> ). أحاول أن أوضح أنه ليس الأمر كذلك أن هذه الأنواع "لا يمكن نقلها".

آه ، نعم ، ثم أوافق. لا يتم تثبيت النوع !DePin دائمًا ، وعندما لا يتم

cramertjwithoutboats شيء واحد لم أنا تماما قادرة على surise بعد، هم ي 'الل ضد إعادة تسمية Unpin ؟ لا يبدو أنك تشعر أنك توافق على أنه يجب إعادة تسميته ، لكنني لست متأكدًا مما إذا كنت تعارض ذلك.

أنا شخصياً لا أعتقد أن المشكلة الرئيسية هنا تكمن في الاسم Unpin وأنه "إذا تمكنا من إعادة تسميته ، فسيكون كل شيء بديهيًا". بينما قد تساعد إعادة التسمية قليلاً (ويبدو أن Relocate / DePin لطيف هنا ...) ، أعتقد أن التعقيد الرئيسي يأتي من مفهوم التثبيت نفسه ؛ إنها بالتأكيد ليست من أسهل المفاهيم التي يمكن فهمها أو شرحها ؛ ولا حتى تقريبا.

لذلك ، أعتقد أن وثائق الوحدة النمطية core::pin تحتاج إلى تعزيز _ بشكل ملحوظ _ وهناك الكثير من الأمثلة التي يجب تضمينها. من شأن الأمثلة الجيدة أن تُظهر حالات الاستخدام الأساسية بالإضافة إلى استخدامات الوظائف غير الآمنة وعمليات التنفيذ غير السليمة.

alexcrichton أنا لست ضد إعادة التسمية ، لا. أعتقد أن Unpin جيد بالفعل ، لكنني سأكون بخير مع DePin ، ولهذا السبب اقترحته. RemoveFromPin هو الاسم "الصحيح" الأكثر وضوحًا ، ولكنه مطول إلى حد الملح النحوي ، لذلك أعتقد أنني سأعارض هذا الاسم على وجه التحديد. ومع ذلك ، فأنا أعارض تأجيل الاستقرار إلى أجل غير مسمى حتى نجد اسمًا يتفق الجميع على أنه الأفضل - أعتقد أن واجهة برمجة التطبيقات لديها بعض التعقيدات المتأصلة التي لن يتم تحسينها أو جعلها أسوأ بشكل كبير بسبب اسم Unpin سمة. أرغب حقًا في الدفع نحو الاستقرار قريبًا من أجل منع المزيد من الاضطراب في الشفرة والمستندات والمناقشات حول futures_api (وبالتالي يمكننا البدء في وضع القطع في مكانها لتحقيق الاستقرار futures_api بحد ذاتها). ربما يتعين علينا تحديد موعد اجتماع VC مخصص لتسوية الأسماء حتى يتمكن كل من لديه رأي من طرح حله ويمكننا الحصول على فرصة عرض نطاق أعلى لتسوية ذلك؟

تصويتي هو std::pin::Reloc (تغيير)

لدي حالتان افتراضيتان (حسنًا ، حقًا واحد فقط ، لكن إعدامان مختلفان) لا أمانع في أن أذكر صراحةً ما إذا كان مسموحًا به أم لا.

يشير Unpin إلى أنه من التافه الانتقال من كل T 's (حيث T: Unpin ) في حالة النوع المثبت (آمل أن أتذكر هذا المصطلح بشكل صحيح من إحدى منشورات مدونة Pin تسليم &mut T .

لذلك لنفترض أنني أريد إنشاء نوع Woof والذي من الممكن دائمًا الانتقال من جميع حالات Woof أثناء وجوده في حالة النوع المثبت إلى النوع غير المثبت- الدولة ، ولكن ليس من التافه القيام بذلك ، وبالتالي لا يمكن تنفيذ Unpin ، هل يُسمح لـ Woof أن يكون لها وظيفة مثل fn unpin(self: Pin<Box<Woof>>) -> Box<Woof> ؟

نفس الشيء بالنسبة لنوع Meow والذي من الممكن فقط في بعض الأحيان الانتقال من مثبت إلى غير مثبت ووظيفة مثل fn unpin(self: Pin<Box<Meow>>) -> Result<Box<Meow>, Pin<Box<Meow>>> .

2 سنتي لدراجاتي:

إذا فهمت بشكل صحيح ، فإن ما يعنيه Unpin حقًا هو أن " Pin ليس له تأثير علي".

ماذا عن شيء مثل BypassPin أو IgnorePin ؟

لذلك لنفترض أنني أريد إنشاء نوع Woof والذي من الممكن دائمًا الانتقال من جميع حالات Woof أثناء وجوده في حالة النوع المثبت إلى حالة النوع غير المثبتة ، ولكن ليس من السهل القيام بذلك و لذلك لا يمكن تنفيذ Unpin ، فهل يُسمح لـ Woof أن يكون لها وظيفة مثل fn unpin (self: Pin>) -> صندوق؟

نعم ، يجب أن يكون ذلك ممكنًا. على سبيل المثال ، إذا كان Woof عنصرًا في قائمة مرتبطة متطفلة ، فيمكنه توفير وظيفة لإزالة العنصر من القائمة ، وإزالة Pin في نفس الوقت (بحجة ذلك لغير -enqueued Woof s ، كلا النوعين متكافئان ، لذا يمكننا فك تثبيته).

يواجه Relocate نفس المشكلة مثل RePin بالنسبة لي ، فقد يشير إلى عملية تسمح بنقل قيمة من موقع مثبت إلى آخر ، وليس إلغاء تثبيت القيمة تمامًا. إنها دلالة أقل قوة من دلالة RePin ، لكنها لا تزال تبدو مربكة بعض الشيء.

قد يشير إلى عملية تسمح بنقل قيمة من موقع مثبت إلى آخر ، وليس إلغاء تثبيت القيمة تمامًا.

في حين أن هذا ليس بالضبط ما تدور حوله هذه السمة ، إلا أنه ليس خاطئًا تمامًا أيضًا: بالنسبة لمعظم حالات الاستخدام ، يكون نقل قيمة من موقع مثبت إلى آخر أمرًا كارثيًا مثل استخدامه بحرية. في الواقع ، نظرًا لأنه يمكن لأي شخص إنشاء Pin<Box<T>> ، فأنا لا أرى حتى سبب قيامك بتمييز أساسي هنا.

بالنسبة لمعظم حالات الاستخدام ، يعد نقل قيمة من موقع مثبت إلى آخر كارثيًا تمامًا مثل استخدامه بحرية.

نعم ، وهذا هو السبب في أن وجود سمة تضيف هذه العملية إلى نوع ما قد يكون مفيدًا (لا يمكن أن تكون سمة علامة مثل Unpin حيث قد تحتاج إلى القيام بأشياء مثل تحديث المراجع الداخلية). لا أقترح أن نضيف شيئًا كهذا الآن ، فقط أنه شيء يمكنني رؤيته يتم تقديمه في المستقبل (إما في std أو طرف ثالث) والذي قد ينتهي بتداخل محير للأسماء.

لا أعرف أي حالات استخدام قوية لها الآن ، لكنني فكرت في استخدام شيء مثله مع المجموعات المثبتة.

حسنًا ، إليك بعض التفكير. كنت أتساءل في البداية عما إذا كان بإمكاننا الحصول على اسم مثل PinInert أو PinNoGuarantees لأن هذا أيضًا هو الوصف ، لكن التفكير في أن ما أريده حقًا هو سمة تصف إجراءً بدلاً من الملكية ، أو على الأقل يجعل التفكير في ذهني أسهل كثيرًا.

مشكلة واحدة مع Unpin (لست متأكدًا من السبب) هي أنه لا يمكنني فهم الأمر في رأسي أن المعنى المقصود هو "إجراء الإزالة من الدبوس ، أو فك التثبيت ، آمن للقيام به ". تنقل السمة كما هي الفعل "فعل فك الدوران" لكن يبدو أنني لا أستطيع أن أفهم ذلك تمامًا عندما قرأته. من الغريب أن يكون لديك Pin<T: Unpin> لأنه إذا كان "إلغاء التثبيت" ، فلماذا يتم وضعه في Pin؟

أتساءل عما إذا كان اسم مثل CanUnpin يمكن أن يعمل؟ وهناك الكثير من هذه ليست عن طريق الصلبة ضمان أو بأخرى (تنفيذ Unpin لا يعني أنك لن إزالته من دبوس، بل يعني فقط يمكنك إزالته من دبوس). كيف يبدو هذا؟ هل CanUnpin مقروء بما يكفي للآخرين؟ قصير كفاية؟

(وجود بادئة Can ينقل الفعل بالنسبة لي بسهولة أكبر بكثير أيضا، وتقول يمكنك إزالته من دبوس ولكن لم تكن بالضرورة دائما ما).


كظل غير ذي صلة ، هناك شيء واحد نسيت أن أذكره سابقًا (آسف لذلك!) هو أنني لا أعتقد أن جميع الطرق المذكورة أعلاه يجب أن تكون بالضرورة طرقًا متأصلة. لقد كان لدينا بالفعل الكثير من الأخطاء حول طرق الاستدلال والصدام ، وإضافة أسماء شائعة جدًا مثل as_ref و as_mut على الأنواع التي تنفذ أيضًا Deref تبدو مشكلة في انتظار حدوث ذلك.

هل تحدث هذه العمليات بشكل شائع بما يكفي لتبرير الموقع الخطير لوضعها؟ (بطبيعتها) أم أنها نادرًا ما تُستخدم بما يكفي لتحمل الطريق الآمن للوظائف المرتبطة؟

نظرًا لأنني على ما يبدو لدي مظهر في هذه اللعبة الآن: يبدو أن CanUnpin قريب جدًا بالنسبة لي من Unpinnable أو شيء مشابه ، وكان انطباعي دائمًا أن المجتمع يستهجن هذه الأنواع من المعدلات في أسماء السمات ، لأن معظم السمات تصف الإجراء الذي يمكن أن يتخذه النوع. الضمني نفسه هو ضمني "يمكن" أو "ممكن" بهذا المعنى. أيا كان ما تم تحديده (والاسم لا يهم إلى الحد المذكور هنا IM-not-so-HO - من المحتمل أن يقوم عدد قليل جدًا من المستخدمين بكتابة هذا) ، أود أن أشجع الجميع على الشعور ببعض الإلحاح حول حل الأسئلة هنا. أنا متحمس لهذا الاستقرار ، وأعلم أن الكثير من الناس كذلك!

تضمين التغريدة

مشكلة واحدة مع Unpin (لست متأكدًا من السبب) هي أنه لا يمكنني فهم الأمر في رأسي أن المعنى المقصود هو "إجراء الإزالة من الدبوس ، أو فك التثبيت ، آمن للقيام به ".

ماذا لو كنت تعتقد أن T: Unpin أنه " T محصن ضد Pin "؟ ثم إذا كان لديك Pin<T: Unpin> فهذا يعني فقط أن لدينا قيمة داخل Pin وهي محصنة ضد التثبيت ، لذا فإن التثبيت هنا موضع نقاش فعال.

أو بعبارة أخرى: Unpin يحيد Pin . لأكون صادقًا ، بعد الكثير من المناقشة ، استوعبت هذا نوعًا ما وأصبح الآن منطقيًا. 😆

لا يتعلق الكثير من هذا بضمان قوي بطريقة أو بأخرى (لا يعني تنفيذ Unpin أنك ستزيله من دبوس ، بل يعني فقط أنه يمكنك إزالته من دبوس).

النقطة المقابلة لهذا هي السمة Send . وهذا لا يعني أنك سوف ترسل قيمة، بل يعني فقط يمكنك إرسالها.

anp أوافق على أن CanUnpin ليس اسمًا رائعًا ، فأنا أحاول أن أبذل قصارى جهدي لاكتشاف اسم أفضل! يبدو أن القليل منهم ما زالوا يشعرون أن هذا يحتاج إلى إعادة التسمية على الرغم من أنه يبدو أنه تم إسقاط جميع الاقتراحات للأسباب نفسها التي أشعر بها أن Unpin يحتاج إلى إعادة التسمية في المقام الأول.

وللتذكير أيضًا ، فإن أي تثبيت للقطارات مثل جميع التغييرات الأخرى ، ومع الإصدار الأسبوع المقبل ، لن يكون هذا بالتأكيد في هذا الإصدار وسيكون مرشحًا للإصدار التالي. هذا يعني أن لدينا 7 أسابيع ، ما يقرب من شهرين ، لنهبط كل هذا لضمان وصوله في أسرع وقت ممكن. بينما أوافق على أن الإلحاح ضروري ، إلا أنه "دعونا لا ننسى هذا الاستعجال" ، وليس "دعونا نحل هذا قبل يوم الاثنين".

stjepang لقد Unpin الآن بعد التفكير في الأمر كثيرًا! تبدو جميع الأسماء البديلة في هذه المرحلة باهتة للغاية ، لذا فقد وصلت إلى النقطة التي سأقبل فيها على توثيق أفضل. وأود أن مثالي مثل العثور على شخص لا يعرف الكثير عن Pin اجهات برمجة التطبيقات لقراءة الوثائق وقال بعد ذلك، على الرغم من أن الاختيار المزدوج انها كافية للتعلم.

أود أيضًا المضي قدمًا وحظر التثبيت رسميًا على الوثائق المحسّنة ، حيث إنه أمر بالغ الأهمية بشكل خاص لهذه المشكلة.

rfcbot قلق تحسين التوثيق

ما أشعر أنه بحاجة إلى توثيق أفضل بشكل ملموس هو:

  • مزيد من النثر في كل طريقة حول سبب كونها آمنة و / أو سبب كونها غير آمنة. على سبيل المثال ، عقد تنفيذ P s DerefMut "يتصرف بشكل معقول" لم يتم توثيقه في Pin::new_unchecked .
  • يجب أن تحتوي كل دالة unsafe على مثال رمز يوضح سبب كونها غير آمنة ، أو على الأقل شرح واضح لسلسلة من الخطوات التي يمكن أن تسوء.
  • أشعر أن مستندات الوحدة يمكن أن تتطرق إلى مزيد من التفاصيل بما يتجاوز مجرد معنى Pin وماذا يعني ذلك. أعتقد أنهم سيستفيدون من معلومات مثل "كيف أن هذا ليس أنواعًا غير منقولة عامة ولكنه شكل من أشكال ذلك" أو "كيف يتم استخدام Pin عمليًا ، على سبيل المثال مع العقود الآجلة"
  • أرغب في رؤية مثال للأدوية و Unpin في التوثيق أو أمثلة الكود. على سبيل المثال ، يبدو أن العديد من شركات الدمج في العقود الآجلة يجب أن تتعامل مع هذا الأمر ، وبالمثل فإن بعض المجمعات تتطلب ذلك على وجه التحديد. بعض الأمثلة على استخدام حالات لكيفية عمل المرء مع الأدوية الجنيسة وكيفية لعبها قد تساعد في فهم Unpin قليلًا.

أشعر بالفضول أيضًا إذا كان لدى الآخرين عناصر ملموسة قابلة للتنفيذ لإضافتها إلى الوثائق أيضًا!

بعد ذلك ، أود أيضًا حظر السؤال self رسميًا باستخدام as_ref ، لكنني أشك في أن هذا سيكون سريع الحل. (آسف مرة أخرى لعدم تذكر طرح هذا في وقت أقرب)

rfcbot تتعلق

هذا يقترح as_ref ، as_mut ، get_ref ، get_mut ، into_ref ، و set كلها على Pin النوع. يذكر الاقتراح أننا لا نفعل ذلك للمؤشرات الذكية بسبب تضارب الأساليب ، ولكن يستشهد بهذه التجربة تظهر أن واجهة برمجة التطبيقات التي تم تنفيذها اليوم Pin API غير متسقة وغالبًا ما ينتهي بها الأمر فقط في الطريق.

ومع ذلك ، فإن أسماء الطرق هذه قصيرة جدًا ولطيفة ومن الشائع جدًا العثور عليها في جميع أنحاء النظام البيئي. واجه فريق libs سلسلة لا تنتهي من الأخطاء في الماضي حيث نضيف تطبيقات السمات وما شابه ، مما يتسبب في حدوث تضارب مع طرق السمات الموجودة في الصناديق المختلفة. هذه الأساليب تبدو عالية الخطورة بشكل خاص بسبب أسمائها. بالإضافة إلى ذلك ، من غير الواضح ما إذا كان بإمكاننا إضافة المزيد من الأساليب إلى Pin في المستقبل حتى لو انتهى الأمر بالأسماء الآن إلى وضع أي اسم مستقبلي مضاف ينطوي على مخاطر عالية للتصادم.

أود أن أكون على يقين من أننا نعيد التفكير في هذا الاختلاف عن الاتفاقية ، فأنا شخصياً قلق بشكل خاص بشأن العواقب وأعتقد أنه سيكون من الرائع إذا تمكنا من إيجاد حل وسط لتجنب هذه المخاطر.

وبينما كنت في ذلك ، لاحظت شيئًا أخيرًا ، ومرة ​​أخرى أعتقد أن هذا سيكون سريعًا جدًا في الحل

rfcbot قلق مربع pinnned مقابل مربع دبوس

هل تم اعتبار الاسم Box::pin لـ Box::pinned ؟ مع وجود Pinned و / أو PhantomPinned يبدو أنه سيكون من الرائع أن يتطابق الاسم مع نوع الإرجاع!

alexcrichton هل MoveFromPin كخيار ؟ أرى أنك كنت مؤيدًا لها في وقت سابق (ويبدو أن العديد من الأشخاص يحبونها أيضًا). بالنسبة للسجل ، فإن الاعتراضات المباشرة التي يمكنني تذكرها ، أو التي أجدها سريعًا عن طريق Ctrl + F-ing ، هي أن "الأسماء التي تمثل عبارات كاملة ... ستكون أحادية جدًا" (withoutboats) وأنها "شديدة الإلزام" ( cramertj).

يجب أن أعترف أن الدوافع في سياق "لقد اعتدت على ... الآن بعد التفكير في الأمر كثيرًا" تجعلني غير مرتاح إلى حد ما. يمكن للبشر أن يعتادوا على أي شيء جوهريًا وبعد ذلك يبررونه. بغض النظر عن الاسم ، ستكون مفاجأة كبيرة إذا لم نعتد عليه في النهاية. (وهذا هو السبب لماذا نختار أسماء -suboptimal الواضح مثل existential type كما المؤقتة المتقبلة في حالات أخرى، في محاولة لتجنب تحولهم دائم).

إن تفضيل وجهات نظر المستخدمين ذوي الخبرة (وهو ما نتمتع به جميعًا!) عن غير قصد على الآخرين الذين سيأتيون إلى الأشياء بأدمغة أحدث هو نوع الخطأ الذي أعتقد أننا بحاجة إلى توخي الحذر دائمًا ضد ارتكابها ، على الرغم من صعوبة ذلك .

على الرغم من أنه ليس بالتأكيد نمط std lib ، إلا أنني أشعر أيضًا أن CanUnpin بطريقة ما يجعل الأمر أكثر وضوحًا كيف تتناسب هذه القطعة مع القطع الأخرى.

من المستحيل اختراع اسم يصف معنى Unpin للمبتدئين دون قراءة الوثائق. Send الصعب أيضًا فهم Sync للمبتدئين ، لكنهم يبدون لطيفين وموجزين ، وكذلك Unpin . إذا كنت لا تعرف ما تعنيه هذه الأسماء ، فيجب عليك قراءة مستنداتهم.

valff هذا صحيح بالفعل ، ولكن هناك عدد قليل جدًا من الأشخاص الذين قرأوا المستندات Unpin لا يزال يسبب لهم صعوبات عقلية كبيرة ، في حين أن الأسماء الأخرى تسبب القليل.

glaebhoerl ، آسف للتوضيح أنا شخصياً معجب أكثر بـ MoveFromPin أو CanUnpin من Unpin . مجرد محاولة للمساعدة في الانتقال إلى نتيجة!

حاولت فهم الاقتراح الحالي ، ربما يمكن لهذا النوع من التقرير المرحلي أن يسلط بعض الضوء الإضافي على التسمية أيضًا.

  • تمديد ضمانات Pin إلى عنوان ثابت حتى Drop يضع متطلبات إضافية على منشئ Pin . كنت سأجد أنه من المفيد أن يتم ذكر تلك الشروط المسبقة اللازمة لاستدعاء unsafe fn new_unchecked(pointer: P) -> Pin<P> مباشرة. يساعد فهم كيفية إنشاء Pin بشكل كبير في فهم مفهومهم ، imo.
  • الملخص المذكور في قضية التتبع ، والمسبق بـ we agreed that we are ready to stabilize them with no major API changes. ، يحتوي على الكثير من واجهات برمجة التطبيقات القديمة. في الوقت نفسه ، يحتوي أيضًا على الكثير من الأفكار حول Drop وإسقاط الدبوس ذي الصلة. كما أنه يحتوي على صيغة صريحة للضمان الإضافي المشار إليه في النقطة الأولى غير الموجودة في هذا التقرير. كان هذا المزيج من المعلومات القديمة والحديثة مربكًا بعض الشيء ، ففكر في نقل جميع المعلومات إلى هذه المشكلة أو الإشارة إلى فقرات قديمة.
  • نظرًا لأن الضمان الإضافي يُشار إليه على أنه slight extension ، فقد توقعت أن يكون هناك طريقة ما لإلغاء الاشتراك فيه. نظرًا لأن التثبيت مرة واحدة يحمل حالة كتابة على هذا المؤشر حتى يتم إسقاطه ، فهناك طريقة ما للعودة من حالة النوع هذه إلى الحالة "العادية". في الواقع ، كان هذا ما اعتقدت أن فعله في البداية هو Unpin لكنني أعتقد أن Unpin أقوى قليلاً في الواقع. تقول إن الحالة المثبتة يمكن أن تتحول بحرية إلى حالة غير مثبتة ، حسب الرغبة. من الجيد أن تكون الواجهة الحالية ضئيلة في هذا الصدد ، لكن يمكن الخلط بين Unpin وبين عملية على النوع الذي يزيل بعض الثوابت الداخلية التي تتطلب حالة pin (مثل إصدار بسيط من Drop ) .

توضيح: أنا شخصياً أفضل MoveFromPin على الأسماء الأخرى ، لكن يمكن القول إنها مصطنعة وفاخرة.

العنصر الأساسي الملموس القابل للتنفيذ الذي يتبادر إلى الذهن ، إلى جانب تحسينات الوثائق المطلوبة بالفعل من قبل alexcrichton ، سيكون شرح المنطق وراء القاعدة الميدانية لإسقاط الدبوس في map_unchecked و map_unchecked_mut . شيء على غرار:

يعد الدبوس بعدم نقل البيانات المشار إليها حتى يتم إسقاطها. نظرًا لإسقاط حقول البنية بعد البنية التي تحتوي عليها ، فإن حالة الدبوس الخاصة بها تمتد إلى ما بعد تنفيذ Drop للبنى نفسها. يعد الإسقاط على حقل ما بعدم الانتقال منه داخل مدمر الهياكل.

ماذا عن اسم ElidePin لسمة العلامة المشتقة تلقائيًا؟

سوف يكتشف أنه يمكن دائمًا معاملة النوع كما لو كان أو يتصرف كما لو كان غير مثبت. ويبدو أن !ElidePin واضح تمامًا أيضًا ، على الرغم من أن ذلك قد يكون غير موضوعي.

لا تحتوي العلامة القياسية على اسم مثالي لفهم التثبيت أيضًا. يبدو أن Pinned يستحضر فكرة أن البنية المحتوية نفسها مثبتة لكن التثبيت ينطبق على المؤشرات وفقط بعد إجراء صريح. هذا ليس حرجًا تمامًا ولكنه ليس ضئيلًا أيضًا ، خاصة أنه قد يكون النوع الذي تمت مواجهته لأول مرة في تنفيذ لنوع مرجعي ذاتي.

معارضتي العامة لـ MoveFromUnpin / RemoveFromUnpin هي أنها شديدة الإلزام وستتراجع عن بيئة العمل اليدوية للتطبيقات اليدوية Future . CanUnpin / DePin كلاهما يبدو جيدًا بالنسبة لي - أتمنى لو كان الأمر أكثر وضوحًا أن Unpin يتبع النمط Read / Write /إلخ. ولكن يبدو أن هذا ليس بديهيًا للناس ، لذا سأقوم بإجراء 1+ لأي شيء يوضح هذا الأمر دون أن يبدو مثل الملح النحوي.

أوافق على أن NotWhateverUnpinBecomes هو على الأرجح أفضل اسم لـ Pinned . ومع ذلك ، فإن Adhere يعني الانتباه والالتزام. : قليلا_ابتسامة_الوجه:

يبدو كل من CanUnpin / DePin جيدًا بالنسبة لي - أتمنى أن يكون أكثر وضوحًا أن Unpin يتبع نمط القراءة / الكتابة / إلخ

أعتقد أن أحد الأشياء التي تجعل Unpin صعبًا ، على عكس Read هو أنها سمة مميزة. Read السهل فهم Read::read - كل ما تحتاج إلى معرفته موجود هناك في trait . إذا كان x هو Read أفهم أنه يمكنني الاتصال بـ x.read() - وبالمثل write مقابل Write ، إلخ. يصعب شرح ذلك X تنفيذ Unpin يعني أن Pin<Ptr<X>> ينفذ DerefMut - مما يعني أنه يمكنك التعامل معه كما لو كان X .

القراءة سهلة الفهم لأن هناك طريقة قراءة :: قراءة

إذا كان بإمكاننا فقط إضافة طرق قابلة للتطبيق دائمًا في تعريفات auto trait + GAT ، فقد يكون لدينا Unpin::unpin - fn unpin<P: DerefFamily>(self: Pin<P::Deref<Self>>) -> P::Deref<Self> ). ..... في التفكير الثاني ، لا أعتقد أن هذا سيجعل أي شخص أقل ارتباكًا ؛)

(في ملاحظة أكثر جدية ، سأدعم Pin::unpin للانتقال من Pin<P<T>> إلى P<T> )

سأدعم Pin :: unpin للانتقال من Pin

> إلى P

هذا يخلط بين مصطلحين في رأسي ، تمامًا مثل الاسم الحالي نفسه. unpin حد كبير مثل عكس ضمانات حالة النوع ، للمقارنة التي قد تكون كما لو كانت هناك طريقة fn unborrow(&'_ T) أو fn unmove(??) . نظرًا لأن pin يقدم ضمانات حتى تكون بعض الذاكرة التي تمثل نوعًا ما هي Drop::drop ed ، فإننا لا نعكس الحالة حقًا ، فالنوع يضمن فقط أن جميع التمثيلات الأخرى تدعم الضمانات المكافئة وبالتالي يمكننا تجاهل هذا . هذا أيضًا هو الاختلاف الرئيسي الذي أراه بين سمات العلامة وشيء مثل io::Read . يتيح أحدهما عمليات للمترجم أو اللغة ، بينما يتيح الآخر عمليات للمبرمج.

علاوة على ذلك ، إنها نقطة رئيسية وهي أنه لا يمكن حاليًا تمثيل هذا بدقة باستخدام الكتابة الصحيحة فقط. استدعاء العملية unpin يجعل الأمر يبدو وكأن هناك دالة عكسية pin . كونها وظيفة أيضًا بشكل خاطئ بعض الشيء يشير إلى أن عملية إلغاء التثبيت هذه مرتبطة بطريقة ما بالعمل الحسابي ، على سبيل المثال into_pointer() سيكون أفضل في هذا الصدد من خلال اتباع اصطلاح تسمية أكثر رسوخًا.

أخيرًا ، أعتقد أن هناك إمكانية لأنواع خاصة لها وظيفة unpin مع العمل الحسابي. قد يكون النوع الذي لديه ثوابت داخلية خاصة جدًا قادرًا على `` إصلاح '' حالته الداخلية بطريقة يمكن أن تقدم واجهة fn unpin(self: Pin<&'a mut T>) -> &'a mut ، حيث تخسر عن طيب خاطر جميع الضمانات Pin لبعض العمر 'a . في هذه الحالة ، لن يتم تطبيق كلتا النقطتين أعلاه. يمكن تصور مثل هذه الوظيفة كما لو كان لها تأثير مكافئ للإسقاط وإعادة البناء في نفس موقع الذاكرة (وبالتالي إزالة حالة النوع بالفعل). وقد يتضمن الحساب ، على سبيل المثال عن طريق نقل بعض المراجع الذاتية إلى التخصيصات الديناميكية.

سيكون من المؤسف أن يجعل الاسم المربك من الصعب على مصممي المكتبات ومنفذيها اختيار أسماء غير مربكة ، من خلال الخلط بين هاتين الفكرتين.

معارضتي العامة لـ MoveFromUnpin / RemoveFromUnpin هي فقط أنها شديدة الكلام وستتراجع عن بيئة العمل للتطبيقات المستقبلية اليدوية.

لا أعتقد أن هذا صحيح ، خاصة بالنسبة لـ MoveFromPin ، والذي يبدو من المعقول كتابته بالنسبة لي - ومع أي نوع من الإكمال التلقائي الذكي أو الغبي ، فإن المشكلة غير موجودة في الغالب على أي حال.

يجب أن يكون أحد الأجزاء المهمة لبيئة العمل هو أيضًا قابلية القراءة وفهم الكود. تلقى Rust بالفعل بعض الانتقادات في الماضي لاختصاره الأشياء بقوة ( fn ، mut ، إلخ) ، مما يجعل قراءة بعض التعليمات البرمجية أكثر صعوبة. بالنسبة للأشياء التي يكون فهمها أكثر تعقيدًا والتي تحقق غرضًا مناسبًا لمعظم المستخدمين ، يجب أن يكون استخدام اسم مفصل ووصفي مقبولًا تمامًا.

rfcbot حل تسمية

حسنًا ، لقد كنت أتذوق لفترة من الوقت وتحدثت أيضًا مع withoutboats شخصيًا حول هذا الأمر. لقد أدركت أنني الآن مرتاح شخصيًا على الأقل مع الاسم Unpin كسمة علامة. نتيجة لذلك ، سأقوم بإزالة اعتراض الحظر (على الرغم من أنه إذا شعر الآخرون في فريق libs بشكل مختلف ، فيرجى إخبارنا!)

السبب الرئيسي في أنني وصلت إلى Unpin هو ما قاله cramertj بالفعل أعلاه ، إنه الاسم الأكثر اصطلاحًا لهذه السمة التي تمكنا من التوصل إليها. جميع أسماء السمات الأخرى التي رأيتها لا تتوافق مع الشريط الاصطلاحي الذي Unpin (أو على الأقل في رأيي).

على الرغم من أنني ما زلت أعتقد أن هناك أسماء أفضل لـ "رأيت للتو اسم هذه السمة وأريد أن أعرف ما تفعله" ، لا أعتقد أن هذه هي المشكلة الصحيحة التي يجب حلها هنا. من الواضح بالنسبة لي في هذه المرحلة أنه لا يمكننا ، في هذا الوقت على الأقل ، اكتشاف اسم مختلف لهذه السمة التي هي أيضًا اصطلاحية ، لكننا بدلاً من ذلك نتبدل في أسماء السمات التي تحل مشكلة مختلفة. فهم Unpin يشبه Send و Sync ، يجب قراءة الوثائق لفهم ما يجري بشكل كامل.


كنقطة توضيحية أخرى ، قمت بإدراج عدد قليل من "اعتراضات الحظر" لكنها عناصر TODO أكثر من حظر الاعتراضات في حد ذاتها. ليس لدي طريقة رائعة للتنقل في مثل هذا الخيط الطويل! في هذا السياق ، أعتقد أنه من الجيد أن يتم نشر العلاقات العامة الخاصة بالتثبيت في أي وقت الآن مع انقضاء FCP لمدة أسبوع أو نحو ذلك الآن. يمكن مناقشة النقاط النهائية حول self / pin / pin بشكل موجز هناك (إذا لزم الأمر ، يمكن تركها مثل الاقتراح أعلاه).

أعتقد أن التوثيق بشكل خاص ليس شرطًا أساسيًا لتحقيق الاستقرار في هذه الحالة. لدينا دورة كاملة (6 أسابيع) لإضافة مستندات قبل أن تصل هذه الأنواع إلى حالة مستقرة ولدينا وقت أطول لدعم التوثيق هنا قبل استقرار القصة الكاملة غير المتزامنة / المنتظرة هذا الكثير من الوقت لتحسين ما هو موجود الآن ، وما هو موجود الآن مفيد للغاية بالفعل!

ماذا تعني كلمة "اصطلاحي" هنا؟ ما هو Unidiomatic في Reloc[ate] أو Escape أو Evade أو Pluck أو Roam ؟ كلهم أفعال ، ولا يمكن أن يخطئ أي منهم في مشكلة السالب المزدوج.

alexcrichton هل هناك سبب يجعل Unpin أكثر اصطلاحًا من Depin أو DePin ؟

أعتقد أن Depin هو بديل قوي جدًا ، ولا يسبب لي نفس الصعوبات العقلية مثل Unpin .

قد يكون أحد الأسباب البسيطة هو أن depin ليس كلمة وأن إلغاء التثبيت هو. أنا شخصياً ليس لدي أي مشكلة في فهم Unpin . أعتقد أنه يتناسب مع تسمية سمات العلامة الأخرى.

jimmycuadra هناك الكثير من الأسماء في Rust والتي ليست كلمات "حقيقية" ، بما في ذلك في stdlib.

سأندهش إذا اعتبر ذلك سببًا مهمًا لاختيار اسم على آخر.

@ باوان إنه سبب مهم. بصفتي متحدثًا أصليًا للغة الإنجليزية ، يبدو لي Depin كما لو أننا نسينا وجود كلمة إلغاء التثبيت وحاولنا إنشاء واحدة. يبدو الأمر خاطئًا بشكل صارخ بالنسبة لي: الكلمة الإنجليزية التي تعني "depinning" هي "unpinning".

سيكون القياس الجيد هو ما إذا كان لدينا واجهات برمجة التطبيقات التي تقول "delock" بدلاً من "unlock".

jaredr بواسطة "اصطلاحي" أعني اتباع الاصطلاحات المعمول بها في المكتبة القياسية مثل (المذكورة سابقًا) Read و Write . لدينا اصطلاح من الأسماء غير الكلامية ، والأفعال ، ومختصرة حيثما أمكن ، ومناسبة للموقف.

جميع الأسماء التي اقترحتها ممكنة ، ولكن Unpin (أو هكذا أشعر على الأقل) هو الأنسب لهذا الإجراء المحدد (ضمان "يمكنك إلغاء تثبيت هذا النوع"). بينما الآخرون ، في حين أن المرادفات فضفاضة لـ Unpin ، أعتقد أنه يتم فقط إعادة التسمية بعيدًا عن كلمة "unpin" وأحيانًا لا تنقل نفس الاتصال مع Pin مثل Unpin هل.

@ Pauan أتفق مع withoutboats على أن Depin لا يبدو وكأنه يشبه jives وكذلك Unpin .

لاحظ aturon في https://github.com/rust-lang/rfcs/pull/2592#issuecomment -438873636 أن:

استخدام Pin ليس أكثر من تفاصيل تنفيذ من اختيار &self مقابل &mut self ؛ على المدى الطويل ، من المحتمل أن يكون Pin نفسه وضعًا مرجعيًا منفصلاً مع دعم اللغة. في كل هذه الحالات ، ما يتم نقله في التوقيع هو الأذونات الممنوحة للمستدعى ، مع حظر الخروج من المرجع Pin .

ظاهريًا ، يشير هذا إلى نوع &pin أصلي أو شيء ما ... لكن أتساءل كيف أن هذا مربعات مع Pin<&mut T> وما شابه. في محادثاتي مع withoutboats وعلى وجه الخصوص cramertj ، لم يكونوا متأكدين على الإطلاق من فكرة وضع مرجع منفصل مع دعم اللغة وكيف يمكننا الوصول إلى هناك من Pin<T> .

قبل تثبيت pin ، سيكون من الحكمة التوفيق بين وجهات النظر هذه للتأكد من أننا على نفس الصفحة. هذه القطعة المهمة من البنية التحتية ؛ لذلك أود بشكل أساسي أن يتوسع آرون في هذا الأمر وأن يزن تايلور في ذلك.

الآخرون ، في حين أن المرادفات الفضفاضة لـ Unpin ، أعتقد أنهم يعيدون التسمية بعيدًا عن كلمة "unpin" وأحيانًا لا ينقلون نفس الاتصال مع Pin كما يفعل Unpin.

alexcrichton هذا في الواقع شيء جيد ، على ما أعتقد؟ مثل Send لنقل / نسخ (=) ​​العملية ، Sync للاقتراض (&) العملية. ربما يتسبب هذا الاتصال في الواقع في مزيد من الارتباك؟

@ crlf0710 ربما! لست متأكدًا من أنني سأتفق مع مثل هذا الاتصال على الرغم من نفسي. Send و Sync أكثر حول ما يمكّنانه ("إرسال" الأنواع إلى سلاسل رسائل أخرى و "مزامنة" الوصول عبر السلاسل) ، وعند تسميتها لم نحاول تجنب تسميتها قريبة من عملية أو أخرى

تضمين التغريدة لذلك ربما يجب أن تكون هذه السمة أيضًا حول ما تمكّنه. ("متحرك (الفعل هنا) من أصل Pin ). أنا لست متحدثًا للغة الإنجليزية ، لكني ما زلت أعتقد أن "عدم الإزعاج" من أصل pin أمر غريب بعض الشيء؟

@ crlf0710 لكن ما تمكّنه السمة ليس <moving> من رقم التعريف الشخصي ، بل <moving out of a Pin> . مشكلة الحركة ومرادفات الحركة هي أنها تعني أن السمة تتحكم في قدرة النوع على التحرك على الإطلاق ، وهو ما لا يفعله. يعتبر الاتصال بـ Pin أمرًا حيويًا لفهم ما تفعله السمة بالفعل.

لذا فإن أكثر الأسماء الاصطلاحية لهذه السمة هو الفعل الذي يعني "الخروج من دبوس" ، حيث تكون كلمة "Unpin" هي الأكثر وضوحًا بالنسبة لي كثيرًا. إليك تعريف ويكتيوناري لـ "unpin":

  1. للفك بإزالة دبوس.
  2. (متعدية ، حسابية ، واجهة مستخدم رسومية) لفصل (رمز ، تطبيق ، إلخ) من المكان الذي تم تثبيته فيه مسبقًا.

withoutboats شكرا Unpin أو أي اسم يقرره فريق الصدأ أخيرًا ، لا أريد منع تثبيت أنواع Pin على الإطلاق ، وأنا أتفهم تمامًا المخاوف بشأن "النقل" وما إلى ذلك.

إنه يشعر أن هناك أدنى "تكرار" في مكان ما. وعلي أن أقنع نفسي: هذا لا يعني "غير قابل للفوز" ، بل العكس. أعتقد بعد مرور بعض الوقت أنني سأعتاد على ذلك إذا كان هذا هو القرار النهائي.

في نفس الوقت أرجو أن تسمحوا لي أن أقدم اقتراحي الماضي: في الواقع أعتقد أن Detach الفعل المذكورة أعلاه أيضا لطيفة جدا، على الرغم من ذلك بقليل عامة جدا. كما قلت ، أنا لست متحدثًا أصليًا ، لذا لا يمكنني التحدث نيابة عن الآخرين. من فضلك فقط انظر إليها على أنها فكرة صغيرة.

كنت أفكر في الإسقاطات الآمنة المنفصلة ، وتوصلت إلى الفكرة التي قد تمكنها. هذا ماكرو لمحاكاة المطابقة مقابل قيم lvalues ​​القابلة للتغيير المثبتة. مع هذا الماكرو يمكننا الكتابة

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

لتحليل Pin<&mut MyStruct> إلى مراجع قابلة للتغيير مثبتة للحقول.

لجعل هذا آمنًا وقابلًا للاستخدام ، سنحتاج إلى شيئين آخرين:

  • النوع Kite لوضع علامة على الحقول "دائمًا- Unpin "
  • اجعل Unpin غير آمن

هذا الأخير ضروري لسلامة الإسقاط. بدون هذا ، يمكننا تحديد " Kite مع توقعات مثبتة" بأمان ، وهذا خطأ في الواقع.

مع وضع ذلك في الاعتبار ، أقترح جعل Unpin غير آمن قبل الاستقرار لترك غرفة لعمليات مفيدة أخرى لتكون آمنة.

qnighy من الممكن أن ينتهك نوع ما ضمانات Drop ، مما يجعل Drop مكافئًا لـ Unpin . جعل Unpin غير آمن لا يجعل أي رمز إضافي آمنًا ، لأن Drop آمن أيضًا ، ولا يمكن تغيير ذلك. لقد تحدثنا عن هذا كثيرًا في مسألة التتبع ، وقد تم ذكره في هذا الموضوع أيضًا.

بشكل أساسي ، لا يمكن جعل إسقاطات الدبوس آمنة بدون القدرة على تأكيد حدود سلبية معينة لا يمكن التعبير عنها في Rust اليوم.

@ crlf0710

في الوقت نفسه ، اسمح لي بتقديم اقتراحي الأخير: في الواقع ، أعتقد أن فعل الفصل المذكور أعلاه لطيف أيضًا ، على الرغم من أنه عام جدًا. كما قلت ، أنا لست متحدثًا أصليًا ، لذا لا يمكنني التحدث نيابة عن الآخرين. من فضلك فقط انظر إليها على أنها فكرة صغيرة.

يبدو الفصل أفضل بكثير من أسماء مثل Move و Relocate ، ولكن يبدو أنه يتعارض مع الاستخدامات المحتملة الأخرى للاستعارة المنفصلة (على غرار كيف يمكن أن يتعارض Escape مع "تحليل الهروب" وما إلى ذلك). لا يوجد سوى الكثير من الاستعارات التي لدينا حول كيفية ارتباط البيانات بالبيانات الأخرى في علوم الكمبيوتر ، مما يجعلني أفكر في ميزة جديدة أخرى لـ Unpin: من خلال التشبث بإحكام على استعارة "الدبوس" ، لا يشغل مساحة للغة المجازية المستقبلية قد نحتاج إلى استخدامها لغرض مختلف ، بالطريقة التي يمكن أن تستخدمها أسماء مثل Detach أو Escape أو Relocate.

withoutboats ليس لدي أي تفضيل خاص لأي اسم أو الكثير من الاستثمار في هذه الدراجة ... لكنني أشعر بالفضول ؛ ما الغرض الآخر الذي يناسبه Detach (إذا توقعت ...)؟

Centril ليس لدي حالة استخدام واضحة في الاعتبار ، لكن يمكنني تخيل بعض حالات الاستخدام المتعلقة بالتدمير على سبيل المثال.

withoutboats نعم هذا منطقي ؛ في صحتك!

withoutboats لست متأكدًا مما إذا كان إدخال Wiktionary هو أفضل دافع لتبرير تسمية Unpin لتمكين move from a pin . تعاني استعارات التمثيل المادي من حقيقة أن الحركة في Rust لا تأخذ شيئًا في العالم. لنكون أكثر دقة ، فإن "رفع" مؤشر مثبت لا يمنحني التحكم في الذاكرة المشار إليها ، ولا يزال تخصيصها وصلاحيتها كتمثيل كائن T مطلوبين ومضمونين بواسطة دلالات المؤشر. ومن ثم ، فإن إلغاء التثبيت لا يمنح تمثيلاً خاضعًا للرقابة بالكامل لـ T ، كما لو كان إلغاء التثبيت. كما أن إدخال القاموس الذي يحدد unpinning بدلالة moving هو في الواقع جزء من الارتباك أكثر من مجرد تبرير لمثل هذا الاسم.

في واجهة برمجة التطبيقات المقترحة ، ليس لأي من الطرق مثل هذا التأثير (وهي ليست في نطاق الدبوس أيضًا). لا أرى طريقة آمنة على سبيل المثال لنقل Pin<Box<T>> إلى Box<T> (وبالامتداد إلى T ) ولست متأكدًا مما إذا كان Unpin يجب أن مثل هذه الاحتمالات القوية. لست متأكدًا تمامًا من مكان كل هذا الاختلاف. ولكن بقدر ما فهمت ، ينطبق Pin على بعض مواقع الذاكرة بينما يضمن Unpin أنه لا شيء في تمثيل T يعتمد على ضمانات الدبوس. ومع ذلك ، هل هذا هو نفس القدرة على إخراج الذاكرة ونسيانها تمامًا؟ لا أعتقد ذلك. سأفكر في مثال أكثر واقعية.

تحرير: بشكل ملموس ، حتى لو كان T هو Unpin ، هل يمكنني الاعتماد على مثيل من T::drop(&mut) يتم استدعاؤه على الذاكرة التي تم تثبيتها ، قبل إلغاء تخصيص تلك الذاكرة؟ بقدر ما أستطيع أن أقول من الشكلية ، يجب أن تكون الإجابة نعم ، لكن الاسم Unpin يوصلني بالعكس.

تحرير 2: Rc يسمح احد لمراقبة Pin<&T> ولكن ل T: Unpin لا يزال يكن لديك drop دعا موقع الذاكرة الأصلي. احتفظ بالمرجع على قيد الحياة خارج الدبوس ، ثم بعد إسقاط الدبوس ، يمكنك الخروج بـ Rc::try_unwrap . https://play.rust-lang.org/؟version=nightly&mode=debug&edition=2018&gist=dec6f6c6d2c0903d87a4a9cefe50a0ca يجيب هذا بشكل فعال على السؤال من خلال الآليات الحالية ولكن هل يعمل على النحو المنشود؟

ربما IgnorePin ؟ إذا كان T هو IgnorePin يمكنك معاملة Pin<Box<T>> أنه &mut T أساسي تجاهل وجود Pin (تتجاهل AIUI أيضًا Box ). التجاهل هو فعل ، أعتقد أن IgnorePin ليس كذلك لكني لست متأكدًا من ماهيته. IgnorePin هو وصفي لما يسمح به ، فهو ليس وصفيًا للقيود الموضوعة على النوع ، لكنه ليس كذلك Unpin .

wmanley كانت لدي فكرة متشابهة جدًا ، ElidePin ، في بعض التعليقات أعلاه على الرغم من أنني في ذلك الوقت لم أتمكن من التعبير بشكل ملموس عن سبب شعور ذلك بمزيد من الدقة. لكنني أتفق على أن "فعل واحد" هو دليل الأسلوب لسمات علامة الصدأ. على الرغم من أنه يسمح أيضًا بإنكار أكثر طبيعية في شكل !ElidePin / !IgnorePin ، فهو ليس الأمثل.

withoutboats سؤال المتابعة: نظرًا لأن الدبوس يبدو محددًا من حيث الذاكرة الأساسية ، كيف يتفاعل Pin مع ZST؟ نظرًا لأن Pinned هو ZST ، فقد يكون ZST إما Unpin أو لا. أود أن أقول بشكل حدسي أن تمثيل الذاكرة الخاص به لا يتم إبطاله رسميًا ، وبالتالي لا يلزم أبدًا استدعاء T::drop(&mut self) ، على غرار الطريقة التي يمكن بها بناء دبوس من ذاكرة &mut 'static _ على سبيل المثال من Box مسرب

هل من الآمن إنشاء Pin<P<T>> بـ T: !Unpin ثم إزالة تثبيت القيمة على الفور ، إذا كان مضمونًا عدم ملاحظة أي شيء للتثبيت؟ هل هو سلوك غير محدد فقط إذا تم نقل القيمة المثبتة بعد أن تم استدعاء طريقة شبيهة بالاقتراع عليها؟

HeroicKatora لسوء الحظ ، من الممكن اليوم تنفيذ Drop لنوع يمكن أن يكون !Unpin بسبب الأدوية الجنيسة ، على سبيل المثال:

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

cramertj شكرًا لك ، لقد أدركت ذلك أيضًا.

cramertj إذن نحن الافتراضي هو T: ?Unpin على الحدود العامة؟ هل هناك سبب آخر وراء عدم التخلف عن السداد إلى T: Unpin للأنواع الحالية مثل Sized ؟ سيعطي بعض الحالات التي يكون فيها ذلك صارمًا بشكل مزعج ولكن هل يمكن أن يتسبب هذا الربط التلقائي الإضافي في حدوث تراجع؟

HeroicKatora سيتطلب ذلك رش حدود ?Unpin على كل نوع في المكتبة القياسية وفي مجموعة من التعليمات البرمجية التي لا تهتم بـ Unpin على الإطلاق.

من الآمن أيضًا إضافة حقل PhantomPinned ، كطريقة أخرى لإنشاء Drop +!

هل هناك سبب آخر وراء عدم التقصير في T: إلغاء التثبيت للأنواع الحالية؟

يعد Unpin مجرد سمة تلقائية مثل Send and Sync ، ولا يتضمن هذا الاقتراح ميزات لغة جديدة. لذلك فهي تحتوي على نفس الدلالات التي تم تعريف السمات التلقائية لها بالفعل ، وهي أنها لا يتم تطبيقها على الأدوية الجنيسة افتراضيًا (على عكس Sized ، وهي سمة مضمنة في المترجم ، وليست سمة تلقائية).

هل هو سلوك غير محدد فقط إذا تم نقل القيمة المثبتة بعد أن تم استدعاء طريقة شبيهة بالاقتراع عليها؟

يجب أن نكون واضحين هنا أن السلوك غير المحدد في هذا السياق ليس في الحقيقة النوع التقليدي من UB. بدلاً من ذلك ، يمكن لهذا الرمز ، الذي يراقب نوعًا في Pin ، وضع افتراضات حول دلالات الملكية لتلك القيمة (أي أنه إذا لم ينفذ Unpin فلن يتم نقله مرة أخرى أو إبطاله إلا بعد تشغيل أداة التدمير). إنه ليس UB بمعنى أنه يفترض من قبل المترجم أنه لن يحدث أبدًا (لا يعرف المترجم ما هو Pin).

لذا ، نعم ، بمعنى أنه يمكنك التحقق من عدم اعتماد أي رمز على الضمان الذي قدمته. ولكن أيضًا ما فعلته لا طائل من ورائه ، حيث لا يمكن لأي رمز أن يلاحظ أن النوع مثبت.

cramertj أرى ، سيكون ذلك مؤسفًا بعض الشيء. أشعر بعدم الارتياح بعض الشيء مع تفاعل Pin مع Drop في المواصفات ولكن ليس في اللغة. تضارب تام بين صحة الواجهة وقابلية الاستخدام وإطلاقها في المستقبل القريب. هل يمكنني الحصول على توضيح بشأن التعديل 2 أعلاه:

يسمح Rc للمرء بمراقبة Pin <& T> ولكن بالنسبة إلى T: لا يزال إلغاء التثبيت غير موجود في موقع الذاكرة الأصلي. احتفظ بالمرجع على قيد الحياة خارج الدبوس ، ثم بعد إسقاط الدبوس ، يمكنك الخروج باستخدام Rc :: try_unwrap. https://play.rust-lang.org/؟version=nightly&mode=debug&edition=2018&gist=dec6f6c6d2c0903d87a4a9cefe50a0ca

HeroicKatora المشكلة في الكود هو أن Mem<'a>: Unpin ، لكن سطر الكود غير الآمن الذي تستخدمه يعتمد على افتراضات لا تنطبق إلا على الأنواع التي لا تطبق Unpin . لقد قمت بتحرير ملخصك لتضمين دليلًا على أن Mem<'a>: Unpin : https://play.rust-lang.org/؟version=nightly&mode=debug&edition=2018&gist=201d1ae382f590be8c5cac13af279aff

أنت تعتمد على Unpin المرتبط عند استدعاء Pin::new ، والذي لا يمكن استدعاؤه إلا على المؤشرات التي ينفذ هدفها Unpin.

لقد تم النظر في الثغرة التي اعتقدت أنك وجدتها ، وهذا هو السبب في عدم وجود طريقة للانتقال من Rc<T: ?Unpin> إلى Pin<Rc<T>> . يجب عليك إنشاء Rc في الدبوس باستخدام Rc::pinned .

withoutboats أردت فقط تأكيد ذلك ، أن T: Unpin بالفعل أيضًا يختار الخروج من مكالمة drop قبل الإبطال. هذا يطرح السؤال ، ألا ينبغي أن يكون هناك أيضًا

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

نظرًا لأنه لا يحمي أي جزء من الواجهة ، ومن المحتمل أن يكون إلغاء تغليف Pin<Box<T>> في Box<T> مفيدًا (لـ T: Unpin بالطبع).

HeroicKatora أنت محق في أن هذه الوظيفة ستكون آمنة. لا أمانع في إضافته ولكني أرغب في تجنب توسيع واجهة برمجة التطبيقات التي نحقق الاستقرار فيها في هذه اللحظة ، نظرًا لأن هذا الموضوع يحتوي بالفعل على مئات التعليقات الطويلة. يمكننا دائمًا إضافته لاحقًا حسب الحاجة تمامًا كما نفعل مع جميع واجهات برمجة التطبيقات القياسية.

أود أن أقول أن كل من تسمية وظيفة Unpin يجعل الكثير من ينظر الشعور مع هذا الأسلوب العكس. ومعرفة أن ضمانات Pin مقيدة بالفعل بـ T: !Unpin . يمكن أيضًا إثبات ذلك بشكل مباشر من خلال وجود مثل هذه الطريقة ، بدلاً من إنشاء فتحات هروب لإظهار الاحتمال: الابتسامة:. وستكون وثائقه مكانًا مثاليًا لشرح القيود (أو ربطها مرة أخرى). (قد يفكر المرء في تسميته unpin بدلاً من into_inner ).

تحرير: سيعمل في الغالب على تعميم ما هو موجود بالفعل.

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

  • fn unpin(self) -> P

له مثيل لـ P=&'a mut T ، أي ما يعادل القيمة المقترحة

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

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

الآن بعد أن تم الاستقرار ، تبدو نقطة PFCP موضع نقاش ، لذلك:

rfcbot إلغاء

هل هناك أي تتبع للتأكد من أن التعليقات التي تم تطويرها بدءًا من https://github.com/rust-lang/rust/issues/55766#issuecomment-437374982 يتم تحويلها إلى مستندات؟ يبدو أننا قد تأخرنا بالفعل عن الإصدار حيث تم تشعب الإصدار التجريبي ... على الرغم من أنه تمت الإشارة صراحةً إلى حدوث ذلك قبل التثبيت: /

هل هناك أي سبب أن هذا لا يزال مفتوحًا؟ Centril قمت بإغلاقه وإعادة فتحه ، هل كان ذلك متعمدًا؟

RalfJung حاولت إلغاء FCP لكنها لم تستمع ؛ alexcrichton هل يمكنك إلغاء FCP؟

هذا مستقر ، لذا أغلق.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات