Rust: قضية تتبع المشبك RFC

تم إنشاؤها على ٢٦ أغسطس ٢٠١٧  ·  101تعليقات  ·  مصدر: rust-lang/rust

مشكلة في التتبع لـ https://github.com/rust-lang/rfcs/pull/1961

العلاقات العامة هنا: # 44097 # 58710
استقرار العلاقات العامة: https://github.com/rust-lang/rust/pull/77872

لكى يفعل:

  • [x] يجب أن يجتاز RFC فترة التعليق النهائية
  • [x] تنفيذ RFC
  • [] استقرار
B-unstable C-tracking-issue Libs-Tracked T-libs

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

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

ال 101 كومينتر

يرجى ملاحظة ما يلي: كسر هذا المؤازرة وباثفايندر.

cc @ rust-lang / libs ، هذه حالة مشابهة لـ min / max ، حيث كان النظام البيئي يستخدم بالفعل اسم clamp ، وبالتالي تسبب إضافته في الغموض . هذا مسموح به لكل سياسة semver ، لكنه مع ذلك يسبب ألم المصب.

الترشيح لاجتماع الفرز يوم الثلاثاء.

أي أفكار في هذه الأثناء؟

أنا نوعا ما مع bluss على هذا واحد لأنه سيكون من الجيد عدم تكراره. ربما يكون "Clamp" اسمًا رائعًا ، ولكن هل يمكننا تجنب ذلك باختيار اسم مختلف؟

restrict
clamp_to_range
min_max (لأنه يشبه الجمع بين الحد الأدنى والحد الأقصى)
قد تعمل هذه. هل يمكننا استخدام الحفرة لتحديد مدى سوء تأثير clamp الواقع؟ clamp معروف جيدًا عبر العديد من اللغات والمكتبات.

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

بالتأكيد. لم أستخدم الحفرة من قبل ، لكن يمكنني التعلم.

Xaeroxe آه آسف ، قصدت الحصول على العلاقات العامة العودة بسرعة. (أنا في إجازة اليوم ، لذا قد تحتاج إلى شخص آخر في libs ، مثل BurntSushi أو alexcrichton ، للمساعدة في الوصول إليه).

أنا أستعد العلاقات العامة الآن. المتعة في عطلة الخاص بك!

العلاقات العامة جاهزة https://github.com/rust-lang/rust/pull/44438

هل يمكن أن يتكون clamp_to_range(min, max) من clamp_to_min(min) و clamp_to_max(max) (مع التأكيد الإضافي على أن min <= max ) ، ولكن يمكن أيضًا استدعاء هذه الدوال بشكل مستقل؟

أفترض أن هذه الفكرة تتطلب RFC.

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

أنا أعيد فتح هذا حتى يظل ترشيح

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

كان واضحًا جدًا منذ البداية أن هذا قد يتسبب في الكسر الذي أحدثه. أنا شخصياً قارنته بـ ord_max_min الذي كسر مجموعة من الأشياء:

وكان الرد على ذلك "تمت إضافة الوظيفة Ord::min [...] قرر فريق libs اليوم أن هذا كسر مقبول". وكانت هذه ميزة TMTOWTDI ذات اسم أكثر شيوعًا ، في حين أن clamp لم يكن موجودًا بالفعل في std تحت شكل مختلف.

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

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

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

(ميتا) فقط انسخ تعليقي في irlo هنا.

إذا اتفقنا على أن # 44438 له ما يبرره ،

  1. قد نحتاج إلى إعادة النظر فيما إذا كان يمكن حقًا تجاهل كسر الاستدلال من النوع المضمون مثل XIB.

    يعتبر تغيير الاستدلال في الكتابة حاليًا مقبولًا بواسطة RFCs 1105 و 1122 حيث يمكن دائمًا استخدام UFCS أو طرق أخرى لفرض نوع. لكن المجتمع لا يحب حقًا الانهيار الناتج عن # 42496 ( Ord::{min, max} ). بالإضافة إلى ذلك ، # 41336 (أول محاولة T += &T ) تم إغلاقها "فقط" بسبب 8 انحدارات من نوع الاستدلال.

  2. عندما نضيف طريقة ، يجب أن يكون هناك فوهة بركان للتأكد من أن الاسم ليس موجودًا بالفعل.

    لاحظ أن إضافة الطرق المتأصلة يمكن أن تتسبب في فشل الاستدلال أيضًا - # 41793 نتج عن إضافة الطرق المتأصلة {f32, f64}::from_bits ، والتي تتعارض مع الطريقة ieee754::Ieee754::from_bits في سمة المصب.

  3. عندما لا يحدد صندوق المصب #![feature(clamp)] ، لا ينبغي أبدًا النظر في المرشح Ord::clamp (لا يزال من الممكن إصدار تحذير متوافق مع المستقبل) ما لم يكن هذا هو الحل الفريد. سيسمح هذا بإدخال طرق سمات جديدة لا "تكسر الإنستا" ، لكن المشكلة ستظل تعود عند الاستقرار.

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

ضرب Max / min نقطة سيئة بشكل خاص فيما يتعلق باستخدام أسماء الطرق الشائعة على سمة مشتركة. لا يجب أن ينطبق الشيء نفسه على المشبك.

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

مع اقتراب التخصص ، لا نفقد أي شيء عن طريق وضع طرق الامتداد في سمة الامتداد.

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

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

لدي بعض المخاوف التي لا داعي للقلق منها.

  • الاسم والتظليل ليسا مثاليين ولكنه يعمل
  • بالنسبة إلى المتجهات والمصفوفات العددية ، أعتقد أن max / min / clamp ليست مثالية ولكن يتم حل ذلك من خلال عدم استخدام Ord على الإطلاق. يود Ndarray عمل المشابك الوسيطة الأولية والعامة (العددية أو المصفوفة) ، لكن Ord لا يتم استخدامه من قبلنا أو من قبل المكتبات المماثلة. لذلك لا تقلق.
  • الأنواع المركبة الموجودة غير العددية: سيحصل BtreeMap على مشبك طريقة مع هذا التغيير. هل هذا منطقي بشكل عام؟ هل يمكن أن ينفذ لها معنى معقولاً بصرف النظر عن الافتراضي؟
  • وضع الاتصال بالقيمة لا يناسب كل تنفيذ. مرة أخرى ، BtreeMap. هل يجب أن يستهلك المشبك 3 خرائط ويعيد إحداها؟

أنواع المركب

أعتقد أنه منطقي تمامًا مثل BtreeSet<BtreeSet<impl Ord>>::range . ولكن هناك حالات معينة يمكن أن تكون مفيدة ، مثل Vec<char> .

وضع الاتصال من حيث القيمة

عندما جاء هذا في RFC ، كانت الإجابة هي استخدام Cow فقط .

بالطبع ، يمكن أن يكون شيئًا من هذا القبيل ، لإعادة استخدام التخزين:

    fn clamp<T>(mut self, low: &T, high: &T) -> Self
        where T: ?Sized + ToOwned<Owned=Self> + Ord, Self : Borrow<T>
    {
        assert!(low <= high);
        if self.borrow() < &low {
            low.clone_into(&mut self);
        } else if self.borrow() >= &high {
            high.clone_into(&mut self);
        }
        self
    }

والتي https://github.com/rust-lang/rfcs/pull/2111 قد تجعل الاتصال مريحًا.

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

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

هل حدث تشغيل فوهة البركان لهذه الميزة؟

أخطط لإحياء طريقة clamp() بعد دمج # 48552. ومع ذلك ، سيتم استقرار RangeInclusive قبل ذلك ، مما يعني أن البديل المستند إلى النطاق أصبح قابلاً للتطبيق الآن (وهو في الواقع الاقتراح الأصلي ، ولكنه تراجع لأن ..= كان غير مستقر للغاية 😄):

// Current
trait Ord {
    fn clamp(self, min: Self, max: Self) -> Self { ... }
}
assert_eq!(9.clamp(6, 7), 7);


// Alternative
trait Ord {
    fn clamp(self, range: RangeInclusive<Self>) -> Self { ... }
}
assert_eq!(9.clamp(6..=7), 7);

يفتح RangeInclusive المستقر أيضًا إمكانيات أخرى ، مثل قلب الأشياء (مما يتيح بعض الاحتمالات المثيرة للاهتمام مع autoref ، ويتجنب تضارب الأسماء تمامًا):

impl<T: Ord + Clone> RangeInclusive<T> {
    fn clamp(&self, mut x: T) -> T {
        if x < self.start { x.clone_from(&self.start); }
        else if x > self.end { x.clone_from(&self.end); }
        x
    } 
} 

    assert_eq!((1..=10).clamp(11), 10);

    let strings = String::from("aa")..=String::from("b");
    assert_eq!(strings.clamp(String::from("a")), "aa");
    assert_eq!(strings.clamp(String::from("aaa")), "aaa");

https://play.rust-lang.org/؟gist=38def79ba2f3f8380197918377dc66f5&version=nightly

لم أقرر ما إذا كنت أعتقد أن هذا أفضل ، على الرغم من ...

سأستخدم اسمًا مختلفًا إذا تم استخدامه كطريقة نطاق.

بالتأكيد سأستمتع بالحصول على الميزة عاجلاً وليس آجلاً ، بغض النظر عن الشكل.

ما هو الوضع الحالي؟
يبدو لي أن هناك إجماعًا على أن إضافة مشبك إلى RangeInclusive قد يكون بديلاً أفضل.
إذن شخص ما يجب أن يكتب RFC؟

ربما لا تكون هناك حاجة إلى RFC كامل في هذه المرحلة. مجرد قرار لاختيار الهجاء:

  1. value.clamp(min, max) (اتبع RFC كما هي)
  2. value.clamp(min..=max)
  3. (min..=max).clamp(value)

سيسمح الخيار 2 أو 3 بتثبيت جزئي أسهل. يمكنك عمل value.clamp(min..) أو value.clamp(..=max) ، بدون الحاجة إلى أساليب clamp_to_start أو clamp_to_end .

egilburg : لدينا بالفعل تلك الأساليب الخاصة: clamp_to_start هو max و clamp_to_end min : wink:

على الرغم من الاتساق جميل.

egilburg Rust لا يدعم التحميل الزائد المباشر. لكي يعمل الخيار 2 مع اقتراحك ، سنحتاج إلى تنفيذ سمة جديدة مقابل RangeInclusive ، RangeToInclusive و RangeFrom ، والتي تبدو ثقيلة الوزن.

أعتقد أن الخيار 3 هو الخيار الأفضل.

1 أو 2 هي الأقل إثارة للدهشة. سأبقى مع 1 لأن الكثير من التعليمات البرمجية سيكون لها القليل من العمل لاستبدال التنفيذ المحلي بالتطبيق القياسي.

أعتقد أنه يجب علينا إما التخطيط لاستخدام _ all_ النطاق * أنواع أو _لا _ منها.

بالطبع ، هذا أصعب بالنسبة لأشياء مثل Range من RangeInclusive . ولكن هناك شيء لطيف حول (0.0..1.0).clamp(2.0_f32) => 0.99999994_f32 .

@ kennytm لذا إذا قمت بفتح طلب سحب بالخيار 3 ، فهل تعتقد أنه سيتم دمجه؟
أو ما رأيك في كيفية المضي قدمًا بعد ذلك؟

EdorianDark لهذا علينا أن نسأل @ rust-lang / libs 😃

أنا شخصياً أحب الخيار 2 ، بـ RangeInclusive فقط. كما ذكرنا فإن "التثبيت الجزئي" موجود بالفعل مع min و max .

أتفق مع SimonSapin ، على الرغم من أنني قام @ kennytm بمسحها سابقًا ، 5 من أصل 7 (الكل ما عدا Swift و Qt) لها القيمة أولاً ، ثم النطاق.

Clamp الآن في إتقانه مرة أخرى!

أنا سعيد ، على الرغم من أنني ما زلت أحاول معرفة التغيير الذي جعل هذا مقبولاً الآن ، بينما لم يكن في # 44097

لدينا الآن فترة تحذير بسبب الرقم 48552 ، بدلاً من كسر الاستدلال على الفور حتى قبل الاستقرار.

هذه أخبار رائعة ، شكرًا لك!

@ kennytm أريد فقط أن أشكرك على العمل الشاق الذي قمت به في تحقيق # 48552 ، و

https://rust.godbolt.org/z/JmLWJi

pub fn clamped(a: f32) -> f32 {
   a.clamp(0.,255.)
}

يجمع إلى:

  vxorps xmm1, xmm1, xmm1
  vmaxss xmm0, xmm1, xmm0
  vmovss xmm1, dword ptr [rip + .LCPI0_0]
  vminss xmm0, xmm1, xmm0

وهو ليس سيئًا للغاية (يتم استخدام vmaxss و vminss ) ، ولكن:

pub fn maxmined(a: f32) -> f32 {
   (0f32).max(a).min(255.)
}

يستخدم تعليمات واحدة أقل:

  vxorps xmm1, xmm1, xmm1
  vmaxss xmm0, xmm0, xmm1
  vminss xmm0, xmm0, dword ptr [rip + .LCPI1_0]

هل هذا متأصل في تنفيذ المشبك ، أم مجرد نزوة لتحسين LLVM؟

kornelski clamp ing a NAN من المفترض أن تحافظ على NAN ، وهو ما لا يفعله maxmined ، لأن max / min الحفاظ على _non_- NAN .

سيكون من الرائع العثور على تطبيق يلبي توقعات NAN ويكون أقصر. وسيكون من الجيد للأطباء أن يعرضوا طريقة التعامل مع NAN. يبدو أن العلاقات العامة الأصلية بها بعض:

https://github.com/rust-lang/rust/blob/b762283e57ff71f6763effb9cfc7fc0c7967b6b0/src/libstd/f32.rs#L1089 -L1094

لماذا يطفو لقط الذعر إذا كان min أو max هو NaN؟ أود تغيير التأكيد من assert!(min <= max) إلى assert!(!(min > max)) ، بحيث لا يكون للحد الأدنى أو الأقصى لـ NaN أي تأثير ، تمامًا كما هو الحال في طرق max و min.

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

يمكنك دائمًا استخدام INF و -INF إذا كنت لا تريد حدًا أعلى أو أدنى ، أليس كذلك؟ مما يجعله منطقيًا رياضيًا ، على عكس NaN. ولكن من الأفضل في معظم الأوقات استخدام max و min لذلك.

Xaeroxe شكرا لك على التنفيذ.

ربما هذا يمكن أن يذهب في الإصدار التالي ، إذا كان سيكسر رمز ثابت؟

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

في معظم الحالات ، إذا كان الإدخال إلى المشبك أحادي الجانب هو NAN ، فمن المفيد أن تكون النتيجة NAN أكثر من أن تكون النتيجة هي حدود التثبيت. لذا ، فإن الدالتين f32::min و f64::max الحاليتين لا تعملان بشكل جيد لحالة الاستخدام هذه. نحتاج إلى وظيفة (وظائف) منفصلة للقط من جانب واحد. (انظر عدد الصدأ / عدد السمات # 122.)

سبب طرح هذا الأمر هو أنه يؤثر على تصميم clamp على الوجهين ، حيث سيكون من الجيد أن يكون للمشابك ذات الوجهين وواجهة واحدة واجهة متسقة. بعض الخيارات هي:

  1. input.clamp(min, max) و input.clamp_min(min) و input.clamp_max(max)
  2. input.clamp(min..=max) ، input.clamp(min..) ، input.clamp(..=max)
  3. input.clamp(min, max) ، input.clamp(min, std::f64::INFINITY) ، input.clamp(std::f64::NEG_INFINITY, max)

مع التنفيذ الحالي ( min و max f64 كمعلمات منفصلة f32 / f64 ) ، سيتعين علينا اختيار الخيار 1 ، والذي أعتقد أنه معقول تمامًا ، أو الخيار 3 ، الذي IMO مطول للغاية. علينا فقط أن ندرك أن التضحية يجب أن تضيف دالتين منفصلتين clamp_min و clamp_max أو أن تطلب من المستخدم كتابة ما لا نهاية موجب / سالب.

من الجدير بالذكر أيضًا أنه يمكننا توفيرها

impl f32 {
    pub fn clamp<T>(self, bounds: T) -> f32
    where
        T: RangeBounds<f32>,
    {
         // ...
    }
}

// and for f64

منذ f32 / f64 نحن نعرف بالفعل كيفية التعامل مع الحدود الحصرية ، على عكس Ord . بالطبع ، ربما نرغب في تغيير Ord::clamp لأخذ الوسيطة RangeInclusive أجل الاتساق. يبدو أنه لم يكن هناك رأي قوي في كلتا الحالتين حول ما إذا كنت تفضل وسيطتين أو وسيطة واحدة RangeInclusive مقابل Ord::clamp .

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

الفرز: واجهات برمجة التطبيقات أدناه غير مستقرة وتشير هنا. هل هناك مشكلات يجب مراعاتها بخلاف معالجة NaN؟ هل يستحق تثبيت Ord::clamp أولاً دون حظره عند معالجة NaN؟

`` صدأ
سمة الحانة Ord: Eq + PartialOrd{
//…
fn clamp (self، min: Self: max: Self) -> ذاتي حيث ذاتي: الحجم {…}
}
ضمني f32 {
مشبك pub fn (self، min: f32، max: f32) -> f32 {…}
}
الضم f64 {
مشبك pub fn (self، min: f64، max: f64) -> f64 {…}
}

SimonSapin سأكون سعيدًا لتحقيق الاستقرار في كل شيء شخصيًا

+1 ، لقد مر هذا عبر RFC كامل ولا أعتقد أن هناك أي شيء تم طرحه منذ ذلك الحين. على سبيل المثال ، ظهرت معالجة NaN بالتفصيل في IRLO وفي مناقشة RFC .

حسنًا ، هذا يبدو عادلاً بدرجة كافية.

تضمينrfcbot fcp

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

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

لا مخاوف مدرجة حاليا.

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

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

هل تم اتخاذ قرار بشأن x.clamp(7..=13) مقابل x.clamp(7, 13) ؟ https://github.com/rust-lang/rust/issues/44095#issuecomment -533764997 يذكر أن أول واحد قد يكون أفضل للتوافق مع المستقبل المحتمل f64::clamp .

@ m-ou-se شاهد المناقشة التي تبدأ من https://github.com/rust-lang/rust/issues/44095#issuecomment -411457313 وأيضًا https://github.com/rust-lang/rust/pull/ 58710 # pullrequestreview -207529970.

أود أن أقول أن هذا حل مؤسف تمامًا لأن .min و .max يتسببان في كثير من الأحيان في حدوث أخطاء أثناء استخدامك .min(...) لتحديد الحد الأعلى و .max(...) لتحديد الأدنى. هذا أمر محير للغاية وقد رأيت الكثير من الأخطاء مع هذا. .clamp(..1.0) و .clamp(0.0..) أكثر وضوحًا.

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

أعلم أنه من المتوقع أن يكون x.clamp(y, z) أكثر توقعًا ، ولكن ربما تكون هذه فرصة للابتكار ؛)

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

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

@ m-ou-se شاهد المناقشة التي تبدأ من # 44095 (تعليق) وأيضًا # 58710 (مراجعة).

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

كان دعم بعض أنواع النطاقات فقط دون البعض الآخر مفاجئًا جدًا للنتيجة

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

إليك التحليل الأكثر فائدة لذلك: https://github.com/rust-lang/rfcs/pull/1961#issuecomment -302600351

Xaeroxe كان دعم بعض أنواع

إذا كنت تفكر في هذا قبل استقرارها ، فهل غيّر الوقت والاستخدام العام رأيك ، أم أنك تعتقد أن الأمر لا يزال كذلك؟

أود أن أزعم أنه لا ينبغي أبدًا تنفيذ النطاقات الحصرية للعوامات على أي حال ، لأنه سيكون لها سلوك مختلف عن الأعداد الصحيحة (النطاق 0..10 يتضمن الحد الأدنى ويستبعد الحد الأعلى ، فلماذا يجب أن يكون النطاق الافتراضي 0.0...10.0 استبعاد كليهما؟). لا أعتقد أنه سيكون مفاجئًا ، على الأقل بالنسبة لي.

varkor ولكن هذا تم تغييره بعد ذلك بعد تعليق واحد في المراجعة ، دون أي مناقشة حول مسألة التتبع.

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

أظن أن الحجة التي تبحث عنها موجودة هنا: https://github.com/rust-lang/rfcs/pull/1961#issuecomment -302600351

ضربني تحرير

لديه الوقت والاستخدام العام غير رأيك

لم يحدث ذلك حتى الآن ، لكن النطاقات هي شيء أستخدمه بشكل نادر جدًا في الترميز اليومي. أنا منفتح على إقناعي بأمثلة الكود وواجهات برمجة التطبيقات الحالية مع دعم النطاق الجزئي. ومع ذلك ، حتى إذا قمنا بحل هذا السؤال ، فلا يزال هناك العديد من النقاط الممتازة الأخرى التي يُطرحها scottmcm في تعليق RFC والتي تحتاج إلى معالجة. على سبيل المثال ، لم يتم تنفيذ Step على العديد من الأنواع مثل Ord ، فهل هذا التغيير النحوي البسيط يستحق خسارة تلك الأنواع؟ علاوة على ذلك ، هل هناك حالة استخدام لمشابك النطاق غير الشاملة؟ بقدر ما أستطيع أن أقول ، لم تشعر أي لغة أو إطار آخر بالحاجة إلى دعم مشبك النطاق الحصري ، فما الفائدة التي نحققها من ذلك؟ كانت النطاقات أكثر صعوبة في التنفيذ بطريقة مرضية ، وجاءت مع العديد من الجوانب السلبية وفوائد قليلة.

إذا كنت سأقوم بتنفيذ هذا باستخدام النطاقات ، فسيبدو مثل هذا.

لذلك هناك عدة أسباب أعتقد أنه لا ينبغي لنا اتباع هذا النهج.

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

  2. لقد قطعنا شوطاً طويلاً في عملية RFC والشيء الوحيد الذي يكتسب من هذه الطريقة هو طريقة أخرى لكتابة .max() أو .min() . لا أريد حقًا إعادة RFC إلى بداية العملية من أجل تنفيذ شيء يمكننا القيام به بالفعل في Rust.

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

الحاجة إلى عمليات لقط من جانب واحد

... الشيء الوحيد المكاسب من هذا هو طريقة أخرى لكتابة .max() أو .min() .

النقطة الأساسية التي كنت أحاول توضيحها هي أنني رأيت هذا التكافؤ الظاهر بين .min() / .max() والمشابك أحادية الجانب تظهر عدة مرات في المناقشة ، لكن العمليات ليست مكافئة لأرقام الفاصلة العائمة بالطريقة التي يجب أن يتعاملوا بها مع NAN .

على سبيل المثال ، ضع في اعتبارك input.max(0.) كتعبير لتثبيت الأرقام السالبة على الصفر. إذا كان input ليس - NAN ، فإنه يعمل بشكل جيد. ومع ذلك ، عندما يكون input هو NAN ، يتم تقييمه بـ 0. . يكاد يكون هذا هو السلوك المرغوب أبدًا ؛ يجب أن يحتفظ التثبيت أحادي الجانب بقيم NAN . (انظر هذا التعليق وهذا التعليق .) في الختام ، .max() يعمل بشكل جيد لأخذ أكبر رقمين ، لكنه لا يعمل بشكل جيد للقط من جانب واحد.

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

كيفية التعبير عن عمليات التثبيت من جانب واحد

.clamp() مع INFINITY

بمعنى آخر ، لا تقم بإضافة عملية لقط من جانب واحد ؛ فقط أخبر المستخدمين باستخدام .clamp() NEG_INFINITY بحدود INFINITY أو NEG_INFINITY . على سبيل المثال ، اطلب من المستخدمين كتابة input.clamp(0., std::f64::INFINITY) .

هذا مطول للغاية ، مما يدفع المستخدمين إلى استخدام .min() / .max() غير الصحيح إذا لم يكونوا على دراية بالفروق الدقيقة في التعامل مع NAN . بالإضافة إلى ذلك ، فإنه لا يساعد في الحصول على T: Ord ، و IMO أقل وضوحًا من البدائل.

.clamp_min() و .clamp_max()

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

حجة المدى

هناك خيار آخر وهو جعل clamp يأخذ وسيطة النطاق. لقد أظهر Xaeroxe طريقة واحدة لتنفيذ ذلك ، لكن هذا التنفيذ له بعض العيوب ، كما ذكر. طريقة بديلة لكتابة التطبيق مشابهة للطريقة التي يتم بها تنفيذ التقطيع حاليًا (السمة SliceIndex ). هذا يحل جميع الاعتراضات التي رأيتها في المناقشة باستثناء القلق بشأن توفير تطبيقات لمجموعة فرعية من أنواع النطاق والتعقيد الإضافي. أوافق على أنه يضيف بعض التعقيد ، لكن IMO ليس أسوأ بكثير من إضافة .clamp_min() / .clamp_max() . بالنسبة إلى Ord ، أقترح شيئًا كهذا:

pub trait Ord: Eq + PartialOrd<Self> {
    // ...

    fn clamp<B>(self, bounds: B) -> B::Output
    where
        B: Clamp<Self>,
    {
        bounds.clamp(self)
    }
}

pub trait Clamp<T> {
    type Output;
    fn clamp(self, input: T) -> Self::Output;
}

impl<T> Clamp<T> for RangeFull {
    type Output = T;
    fn clamp(self, input: T) -> T {
        input
    }
}

impl<T: Ord> Clamp<T> for RangeFrom<T> {
    type Output = T;
    fn clamp(self, input: T) -> T {
        if input < self.start {
            self.start
        } else {
            input
        }
    }
}

impl<T: Ord> Clamp<T> for RangeToInclusive<T> {
    type Output = T;
    fn clamp(self, input: T) -> T {
        if input > self.end {
            self.end
        } else {
            input
        }
    }
}

impl<T: Ord> Clamp<T> for RangeInclusive<T> {
    type Output = T;
    fn clamp(self, input: T) -> T {
        assert!(self.start <= self.end);
        let mut x = input;
        if x < self.start { x = self.start; }
        if x > self.end { x = self.end; }
        x
    }
}

بعض الأفكار حول هذا:

  • يمكننا إضافة تطبيقات للنطاقات الحصرية حيث T: Ord + Step .
  • يمكننا الاحتفاظ بالسمة Clamp ليلة فقط ، على غرار السمة SliceIndex .
  • لدعم f32 / f64 ، يمكننا ذلك

    1. استرخاء عمليات التنفيذ إلى T: PartialOrd . (لست متأكدًا من سبب التنفيذ الحالي لـ clamp على Ord بدلاً من PartialOrd . ربما فاتني شيء في المناقشة؟ يبدو أنه PartialOrd سيكون كافيا.)

    2. أو اكتب تطبيقات خاصة بـ f32 و f64 . (إذا رغبت في ذلك ، يمكننا دائمًا التبديل إلى الخيار i لاحقًا دون تغيير كسر.)

    ثم تضيف

    impl f32 {
      // ...
      fn clamp<B>(self, bounds: B) -> B::Output
      where
          B: Clamp<Self>,
      {
          bounds.clamp(self)
      }
    }
    
    impl f64 {
      // ...
      fn clamp<B>(self, bounds: B) -> B::Output
      where
          B: Clamp<Self>,
      {
          bounds.clamp(self)
      }
    }
    
  • يمكننا تنفيذ Clamp للنطاقات الحصرية بـ f32 / f64 لاحقًا إذا رغبت في ذلك. (علّق scottmcm على أن هذا ليس واضحًا لأن std لا يحتوي عمداً على f32 / f64 . لست متأكدًا من سبب std ليس لديه هذه العمليات ؛ ربما مشاكل مع أرقام غير عادية؟ بغض النظر ، يمكن معالجة ذلك لاحقًا.)

    حتى إذا لم نقم بإضافة تطبيقات Clamp للنطاقات الحصرية بـ f32 / f64 ، فأنا لا أوافق على أن هذا سيكون مفاجئًا للغاية. كما يشير varkor ، يتعامل Rust بالفعل مع أنواع Copy و Iterator / IntoIterator . (IMO ، هذا ثؤلول std ، لكنه مثال واحد على الأقل يتم فيه التعامل مع أنواع النطاق بشكل مختلف.) بالإضافة إلى ذلك ، إذا حاول شخص ما استخدام نطاق خاص ، فسيكون من السهل فهم رسالة الخطأ ( "السمة المقيدة std::ops::Range<f32>: Clamp<f32> غير راضية").

  • لقد صنعت Output نوعًا مرتبطًا بأقصى قدر من المرونة لإضافة المزيد من عمليات التنفيذ في المستقبل ، ولكن هذا ليس ضروريًا تمامًا.

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

مقارنة الخيارات

نهج "استخدام .clamp() مع INFINITY " له عيوب كبيرة ، كما ذكر أعلاه.

الأسلوب "الموجود .clamp " + .clamp_min() + .clamp_max() له العيوب التالية:

  • إنها مطولة أكثر ، على سبيل المثال input.clamp_min(0) بدلاً من input.clamp(0..) .
  • لا يدعم النطاقات الحصرية.
  • لا يمكننا إضافة المزيد من تطبيقات .clamp() في المستقبل (بدون إضافة المزيد من الأساليب). على سبيل المثال، لا يمكننا أن نؤيد تحامل على u32 قيمة مع u8 حدود، وهي ميزة طلب من المناقشة RFC . قد يتم التعامل مع هذا المثال المعين بشكل أفضل باستخدام وظيفة .saturating_into() ، ولكن قد تكون هناك أمثلة أخرى حيث قد يكون المزيد من تطبيقات التثبيت مفيدة.
  • قد يتم الخلط بين شخص ما بين .min() و .max() و .clamp_min() و .clamp_max() للتثبيت أحادي الجانب. (التثبيت بـ .clamp_min() مشابه لاستخدام .max() ، والتثبيت بـ .clamp_max() مشابه لاستخدام .min() .) يمكننا في الغالب تجنب هذه المشكلة عن طريق تسمية عمليات التثبيت من جانب واحد .clamp_lower() / .clamp_upper() أو .clamp_to_start() / .clamp_to_end() بدلاً من .clamp_min() / .clamp_max() ، على الرغم من ذلك مطول أكثر ( input.clamp_lower(0) مقابل input.clamp(0..) ).

نهج حجة النطاق له العيوب التالية:

  • التنفيذ أكثر تعقيدًا من إضافة .clamp_min() / .clamp_max() .
  • إذا قررنا عدم تنفيذ أو عدم تنفيذ Clamp لأنواع النطاقات الحصرية ، فقد يكون هذا مفاجئًا.

ليس لدي رأي قوي حول "النهج الحالي .clamp " + .clamp_min() + .clamp_max() مقابل أسلوب وسيطة النطاق. إنها مقايضة.

Xaeroxe يضاعف مقدار التفرع الذي يحدث في الوظيفة من أجل استيعاب حالة استخدام ما زلنا غير متأكدين من وجودها. لا يمكنني الحصول على هذا لتظهر في المعايير.

ربما سيتم تحسين الفرع الإضافي بواسطة LLVM؟

على لقط من جانب واحد

نظرًا لأن التثبيت شامل على كلا الجانبين ، يمكن للمرء فقط تحديد min / max على اليسار / اليمين للحصول على سلوك التثبيت أحادي الجانب فقط. أعتقد أن هذا مقبول تمامًا ، ويمكن القول إنه أجمل من .clamp((Bound::Unbounded, Inclusive(3.2))) حيث لا يوجد نوع Range* يناسب أي حال:

x.clamp(i32::MIN, 10);
x.clamp(-f32::INFINITY, 10.0);

ليس هناك خسارة في الأداء ، لأن LLVM قادرة بشكل تافه على تحسين الجانب الميت بعيدًا: https://rust.godbolt.org/z/l_uBLO

قد يكون بناء جملة النطاق رائعًا ، ولكن clamp أساسي بما يكفي لجعل منطقتين منفصلتين على ما يرام ويسهل فهمهما.

ربما يمكن إصلاح معالجة min / max NaN من تلقاء نفسها ، على سبيل المثال عن طريق تغيير تنفيذ الأساليب المتأصلة في f32 ؟ أو تخصص PartialOrd::min/max ؟ (مع علم إصدار ، بافتراض أن Rust تمكن من إيجاد طريقة لتبديل الأشياء في libstd).

scottmcm يجب عليك التحقق من RangeToInclusive .

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

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

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

    • باستخدام التطبيق الجديد المقدم من @ jturner314 ، أصبح لدينا الآن القدرة على إضافة المزيد من القيود على أنواع معينة من Range* ، مثل Ord + Step لإرجاع قيم النطاقات الحصرية بشكل صحيح. لذلك ، على الرغم من أن أداة تثبيت النطاق الحصرية في كثير من الأحيان ليست ضرورية حقًا ، يمكننا في الواقع قبول النطاق الكامل للنطاقات هنا ، دون المساس بواجهة النطاقات التي لا تحتوي على هذه القيود التقنية.
  • يمكننا فقط استخدام Infinity / Min / Max للقط من جانب واحد.

    • هذا صحيح ، وجزء كبير من السبب في أن هذا التغيير ليس حقًا تفويضًا قويًا في رأيي. لدي إجابة واحدة فقط عن هذا ، وهي أن بناء الجملة Range* يتضمن عددًا أقل من الأحرف واستيرادًا أقل لحالة الاستخدام هذه.

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

أشعر بالفضول إذا كان هذا الخط الفكري لديه أي جاذبية مع الآخرين الذين يؤيدون تثبيت RFC كما هو.

أعتقد أنه سيكون من الأفضل ترك Clamp بالشكل الحالي ، لأنه الآن مشابه جدًا للغات الأخرى.
عندما عملت على طلب السحب رقم 58710 ، حاولت استخدام تطبيق يعتمد على النطاق.
لكن rust-lang / rfcs # 1961 (تعليق) ) أقنعني أنه أفضل في الشكل القياسي.

أعتقد أنه سيكون من المنطقي وجود سمة #[must_use] في الوظيفة ، حتى لا يربك الأشخاص الذين لم يعتادوا على كيفية عمل أرقام الصدأ. وهذا يعني أنه يمكنني بسهولة أن أرى شخصًا يكتب الكود التالي (غير صحيح):

let mut x: f64 = some_number_source();
x.clamp(0.0, 1.0);
//Proceeds to assume that 0.0 <= x <= 1.0

بشكل عام ، يأخذ الصدأ منهج (number).method() للأرقام (بينما تستخدم اللغات الأخرى Math.Method(number) ) ، ولكن حتى مع وضع ذلك في الاعتبار ، سيكون من الافتراض المنطقي أن هذا يمكن أن يعدل number . هذه نوعية الحياة أكثر من أي شيء آخر.

تمت إضافة السمة [must_use] مؤخرًا .
@ Xaeroxe هل توصلت إلى شيء ما للمشابك القائمة على النطاق؟
أعتقد أن الوظيفة كما هي الآن من شأنها أن تتناسب بشكل أفضل مع الوظائف الرقمية الأخرى للصدأ وأود البدء في تثبيتها مرة أخرى.

في هذه اللحظة لا أرى أي سبب للذهاب مع المشبك القائم على النطاق. نعم ، دعنا نضيف السمة must_use ونعمل على تحقيق الاستقرار.

SimonSapinscottmcm هل يمكننا استئناف عملية الاستقرار؟

كما قال @ jturner314 ، سيكون من الرائع أن يكون لديك مشبك على PartialOrd ، بدلاً من Ord ، لذلك يمكن استخدامه أيضًا على العوامات.

لدينا f32::clamp و f64::clamp المتخصص في هذا الإصدار بالفعل.

هذا ما أحاول القيام به:

use num_traits::float::FloatCore;

struct Foo<T> (T);

impl<T: FloatCore> Foo<T> {
    fn foo(&self) -> T {
        self.0.clamp(1, 10)
    }
}

fn main() {
    let foo = Foo(15.3);
    println!("{}", foo.foo())
}

رابط إلى الملعب.

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

يتطلب التنفيذ الحالي Eq ، على الرغم من أنه لا يستخدمه.

كان مصدر القلق الرئيسي مع PartialOrd هو أنه يوفر ضمانات أضعف ، مما يضعف بدوره ضمانات المشبك. قد يهتم المستخدمون الذين يريدون أن يكون هذا على PartialOrd بوظيفة أخرى كتبتها https://docs.rs/num/0.2.1/num/fn.clamp.html

ما هي هذه الضمانات؟

توقع طبيعي إلى حد ما هو أنه إذا كان x.clamp(a, b) == x ثم a <= x && x <= b . هذا غير مضمون مع PartialCmp حيث x قد لا يضاهي إما a أو b .

أتيت هنا اليوم بحثًا عن clamp() الذي لم يتم تذكره بشكل غامض واقرأ المناقشة باهتمام.

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

#![allow(unstable_name_collisions)]

pub trait Clamp: Sized {
    fn clamp<L, U>(self, lower: L, upper: U) -> Self
    where
        L: Into<Option<Self>>,
        U: Into<Option<Self>>;
}

impl Clamp for f32 {
    fn clamp<L, U>(self, lower: L, upper: U) -> Self
    where
        L: Into<Option<Self>>,
        U: Into<Option<Self>>,
    {
        let below = match lower.into() {
            None => self,
            Some(lower) => self.max(lower),
        };
        match upper.into() {
            None => below,
            Some(upper) => below.min(upper),
        }
    }
}

#[test]
fn test_clamp() {
    assert_eq!(1.0, f32::clamp(2.0, -1.0, 1.0));
    assert_eq!(-1.0, f32::clamp(-2.0, -1.0, 1.0));
    assert_eq!(1.0, f32::clamp(2.0, None, 1.0));
    assert_eq!(-1.0, f32::clamp(-2.0, -1.0, None));
    assert_eq!(2.0, f32::clamp(2.0, -1.0, None));
    assert_eq!(-2.0, f32::clamp(-2.0, None, 1.0));
}

إذا تم تضمين هذا في std ، فيمكن أيضًا تضمين تطبيق شامل لـ T: Ord ، والذي سيغطي المخاوف التي أثيرت حول تنفيذ PartialOrd .

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

أعتقد أنه يجب أن يتصرف clamp(a,b,c) بنفس الطريقة التي يتصرف بها min(max(a,b), c) .
نظرًا لأن max و min لم يتم تنفيذهما لـ PartialOrd فلا يجب أن clamp .
تمت مناقشة المشكلة مع NaN بالفعل.

تضمين التغريدة min ، max يجب أن تتطلب فقط PartialOrd.

تم تعريفnoonien min و max منذ Rust 1.0 ويتطلبان Ord ولهما تعريف f32 و f64 .
ليس هذا هو المكان المناسب لمناقشة هذه الوظيفة.
هنا يمكننا فقط الحرص على أن min و max و clamp يتصرفون بشكل مشابه وليس مفاجئًا.
تحرير: لا أحب الموقف مع PartialOrd وأفضّل أن يقوم float بتنفيذ Ord ، لكن هذا لا يمكن تغييره بعد 1.0.

لقد تم دمج هذا وعدم استقراره منذ حوالي عام ونصف الآن. كيف نشعر حيال تثبيت هذا؟

أود تثبيت هذا!

إذا كان تعارض اسم الأسلوب clamp يبدو وكأنه مشكلة ، فقد اقترحت تغيير دقة الاسم في وقت ما في https://github.com/rust-lang/rust/pull/66852#issuecomment -561667812 ، وسيساعد ذلك مع هذا أيضا.

Xaeroxe أعتقد أن العملية هي تقديم العلاقات العامة الخاصة بالاستقرار وطلب إجماع فريق libs على ذلك. يبدو أن t-libs مثقل ولا يمكنه مواكبة الأشياء غير fcped.

matklad بدأ بالفعل اقتراح FCP العام الماضي على https://github.com/rust-lang/rust/issues/44095#issuecomment -544393395 ، لكنه عالق نظرًا لوجود مربع اختيار واحد متبقي.

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

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

https://github.com/rust-lang/rust/issues/44095#issuecomment -544393395 لا يزال في انتظار انتباهك

لقد تغير فريق libs قليلاً منذ أن بدأ FCP. ما رأيكم جميعًا في مجرد بدء FCP جديد في العلاقات العامة لتحقيق الاستقرار؟ يبدو أن هذا لا ينبغي أن يستغرق وقتًا أطول من انتظار مربعات الاختيار المتبقية هنا.

LukasKalbertodt بخير من قبلي ، هل تمانع في

إلغاء FCP هنا ، لأن هذا FCP حدث الآن في PR الاستقرار: https://github.com/rust-lang/rust/pull/77872#issuecomment -722982535

fcpbot إلغاء

أوه

rfcbot إلغاء

تم إلغاء اقتراح @ m-ou-se.

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