مشكلة في تتبع rust-lang / rfcs # 2000
التحديثات:
إذا كنت تريد مساعدة، نلقي نظرة على القضايا الأدوية CONST مفتوحة ، وتتردد فيvarkor بينغ،eddyb،yodaldevoid، @ اولى-obk أوlcnr للمساعدة في البدء!
منع الاستقرار:
قضايا التنفيذ المتبقية:
FIXME(const_generics)
.FIXME(const_generics:defaults)
).has_infer_types
.{X * 2}
.ConstEvaluatable
، و WF([T; expr])
يتطلب الآن ConstEvaluatable(expr)
، حيث يتم تقييم expr
بتباطؤ (حتى لو كان مجرد عدد صحيح حرفية). يتطلب تحقيق هذا الإسناد أن يتم تقييم التعبير بنجاح ، بينما يتجاهل التسوية الخطأ ويترك ببساطة التعبير Unevaluated
الذي وجده دون تغيير ، وهو ما يحدث تقريبًا مع توقعات النوع المقترنة. أتوقع أن يتوسع نفس النظام ليشمل الأدوية العامة.عبرEpicatSupercell عن اهتمامه بالعمل على هذا ،
وهذا يعني أننا بحاجة إلى التطبيع البطيء لـ
نقاط طريق التنفيذ (لمزيد من التوجيه المباشر ، ابحث عن @eddyb
على Gitter أو eddyb
على IRC):
const
إلى جانب معلمات النوعparse_generic_params
- تحليل const IDENT: Type
DefId
ty::Generics
- أضف معلمات const
إلى جانب معلمات النوعgenerics_of
- إنشاء ty::ConstParameterDef
من hir::ConstParam
Def
- أضف متغيرًا لمعلمات const
with_type_parameter_rib
- يدعم كلا النوعين و const
genericsConstVal
- أضف متغير Param
أقرب إلى ty::TyParam
TyArray
بطول يساوي ExprPath
والذي تم حله إلى Def::ConstParam
يجب أن يستخدم ConstVal::Param
بدلاً من ConstVal::Unevaluated
- في مماثل أزياء لكيفية تحول Def::TyParam
إلى ty::TyParam
subst::Kind
- دعم &ty::Const
وتحقق من as_const
أيضًا في الأماكن التي يتم فيها تحديد as_type
و as_region
ConstVal
- أضف متغير InferVar
أقرب إلى ty::ReVar
/ ty::TyInfer(TyVar(_))
InferCtxt
- const
نظرائهم إلى int_unification_table
و UnifyKey
ty::relate::{Relate,TypeRelation}
- الدعم المتعلق بـ ty::Const
، وتعامل مع ConstVal::InferVar
بطريقة مشابهة لكيفية عمل super_combine_tys
للأنواعلاحظ أن كل هذا يجب أن يسمح impl<T, const N: usize> Trait for [T; N] {...}
، لكن لا يتم تمرير تعبير ثابت إلى نوع / وظيفة ، على سبيل المثال ArrayVec<T, 3>
.
أود أن أحصل على طعنة في هذا :)
jplatteeddyb هل من أخبار عن هذا؟
samsartor كان هناك إعادة بناء ديون يجب القيام به قبل أعمال التنفيذ الرئيسية. لقد أوشك ذلك الآن على الانتهاء (في انتظار التعليقات حاليًا). لا أعرف في الواقع مقدار العمل بعد ذلك. كان تحليل المعلمات الثابتة هو ما بدأت به في البداية ، قبل إعادة الهيكلة. لم يتم ذلك ولكن سأتمكن من إنجاز ذلك قريبًا نسبيًا.
jplatte سيكون
لا يوجد علاقات عامة بعد. يمكن العثور على كل عملي هنا .
عمل جيد حتى الآن jplatte 🍻
يوجد الآن علاقات عامة للأعمال الأساسية ( Generics
إعادة بناء ديون): # 45930
أعتقد أن هذا تم تضمينه بالفعل ولكن سيكون من الجيد التعامل مع أسلوب طي النمط C ++ للتعامل مع مصفوفات الأبعاد بأطوال متفاوتة على غرار الجبر الخطي ، IE a 4x4 [[f64؛ 4]؛ 4] أو مصفوفة أبعاد 4x3x5x6 [[[[] f64؛ 6]؛ 5]؛ 3]؛ 4] وأن تكون قادرًا على الالتفاف بشكل صحيح وإنشاء طرق متخصصة لكل من عمليات التنفيذ المناسبة للسمات العددية المتجهات ذات الأبعاد المناسبة ، إلخ. راجع https://gist.github.com/huhlig / 8b21850b54a75254be4b093551f8c2cb لمثال أولي.
لا أتذكر أي شخص اقترح تعبيرات مطوية لـ Rust من قبل ، ناهيك عن ذلك كجزء من RFC هذا. ولكن نظرًا لأن هذا هو Rust ، فهل هناك أي سبب لعدم تمكننا من تنفيذ تعبيرات الطي كماكرو عادي ، بدلاً من بناء جملة مخصص جديد؟
ما هي الخطوات التالية الآن بعد دمج # 45930؟ تضمين التغريدة
jplatte أعتقد أنك قصدت ذكر kjetilkjeka.
شكرا للتحديث! أنا متأكد من أنني لست الشخص الوحيد الذي يتطلع إلى هذه الميزة. ثابر على العمل الجيد!
jplatte لا تريد أن تكون غير صبور ، ولكن هل كان هناك أي عمل على هذا؟ هل تحتاج مساعدة؟ هل يجب على أحد المساعدة؟
@ est31 آسف. لم يتح لي الوقت للعمل على هذا منذ فترة ، ولست متأكدًا تمامًا متى سيكون لدي الوقت. ربما يكون من الأفضل لشخص آخر أن يستمر من حيث توقفت. أعتقد أن جزء الإعراب قد تم في الغالب. هناك مكانان في الكود حيث لم أكن متأكدًا مما يجب فعله في حالة كون المعلمة العامة معلمة ثابتة:
لا توجد أيضًا أي اختبارات لتحليل العوامل الثابتة حتى الآن (ولرمز الطباعة الجميل الذي قمت بتحديثه في نفس الوقت). لست متأكدًا من المعلومات الأخرى التي يمكنني تقديمها والتي ستكون مطلوبة / مفيدة لشخص آخر لمواصلة العمل على هذا ، ولكن لا تتردد في الاتصال بي إذا كان هناك شيء غير واضح بشأن الكود الخاص بي.
jplatte ~ None
في الأول وليس في الثانية ~~ (ج جpnkfelixnikomatsakis)
تحرير : لا شيء تفعله في كلتا الحالتين.
eddyb لأول مقتطف مرتبط ، هل أنت متأكد من أنه يجب إرجاع None
؟ قد لا أفهم ما يجري هنا ، لكن يبدو لي أنه لا ينبغي فعل أي شيء. إذا تم إرجاع None
سيتم تخطي المعلمات الأخرى التي قد تكون غير آمنة.
yodaldevoid معذرة ، أنت على حق ، لم أدرك أن هذا كان على Generics
.
أود اختيار هذا من حيث توقفjplatte . لقد كنت أعمل بعيدًا في هذا لمدة يومين حتى الآن ، وأقوم بالاطلاع على إرشادات التوجيه الخاصة بـ
yodaldevoid عظيم أن نسمع. لا أعرف شيئًا عن Gitter ، لكنك ستحصل بالتأكيد على الكثير من الإرشادات حول #rustc و / أو # rust-internals على IRC!
yodaldevoid : هل ستكون فعلته حتى الآن هنا .) ربما يمكننا الدردشة على IRC (#rustc or # rust-internals) حول هذا الموضوع؟
varkor يبدو أنك تقدمت أكثر مما حصلت عليه. سأكون بالتأكيد على استعداد للتعاون. سأحاول الحصول على IRC في وقت ما وفي نفس الوقت لمعرفة ما إذا كنت قد أنجزت أي شيء لم تفعله بالفعل.
هل هناك أي تقدم في هذا؟
أنا أكتب رمزًا للدمج ، وأحتاج حقًا إلى أنواع ثابتة.
@ qwerty19106
يتم إحراز تقدم في هذا ، وإن كان ببطء. varkor وأنا نعمل على هذا الأمر وإيقافه كما كان لدينا الوقت. لقد أحرزت بعض التقدم هذا الأسبوع ونرى الضوء في نهاية النفق للاستخدام الأساسي.
إلى جانب تطبيق الأدوية العامة ، قمنا (varkor) ببعض التنظيف لجعل كل هذا ممكنًا (انظر # 48149 و # 48523). أعتقد أن الخطة الحالية هي انتظار تنفيذ طلبي السحب هذين قبل استخدام الأدوية العامة ، لكن يمكن لـ varkor التحدث أكثر عن ذلك.
أنا أتفهم حقًا حاجتك للأدوية العامة للعمل المضمن. لقد بدأت في هذا لأنني أيضًا أريد حقًا أنواعًا ثابتة حتى أتمكن من تنظيف مساحات كبيرة من التعليمات البرمجية المضمنة وجعلها آمنة.
TL ؛ DR: التقدم مستمر ، لكن هذا معقد. أشعر بك في المقدمة.
بالنسبة إلى مربع الاختيار "التوثيق" ، سيكون من الرائع الحصول على شيء ما في دليل rustc .
شكرا yodaldevoid على ردك. سوف أتطلع إلى نهاية عملك.
تحديث لأولئك الفضوليين (منذ أن كنت فضوليًا أيضًا). رد: الممثلين الرئيسيين المذكورين أعلاه : تم دمج # 48523 و # 48149 يحرز تقدمًا باطراد.
@ مارك- im الأشياء الجيدة! عمل رائع بواسطةvarkor. ما هو موعد إيتا تقريبًا ، هل تعلم؟ :-)
alexreg https://github.com/rust-lang/rust/issues/51192#issuecomment -394126083
في صحتك ، @ flip111.
يبدو أن ثاني أكبر عملية إعادة بناء ديون PR # 48149 قد تم دمجها :)
/ سم مكعب لي
التالي varkor PR # 51880
أردت فقط تقديم تحديث سريع ، حيث أعلم أن بعض الأشخاص يسألون عن التقدم في الأدوية العامة الثابتة.
لإعطاء بعض السياق ، في مارس / آذار ، كان لدي أنا و yodaldevoid تنفيذ أولي كان على
علاوة على ذلك ، فقد تقرر أن كود المعلمات العامة بحاجة إلى التنظيف بشكل عام قبل معالجة العوامل الثابتة ، لتحسين إمكانية القراءة ، ولكن أيضًا لارتكاب أخطاء حيث نسينا التعامل مع الأدوية العامة الثابتة في حالة معينة أصعب صنع. تم ذلك في https://github.com/rust-lang/rust/pull/48523 ، https://github.com/rust-lang/rust/pull/48149 وسيتم إكماله في https: // github. كوم / رست لانج / صدأ / سحب / 51880. كانت هذه أكثر انخراطًا قليلاً مما كنت أتوقعه في البداية ، وقد استغرقت وقتًا أطول قليلاً للمضي قدمًا مما كان متوقعًا.
في غضون ذلك ، نعمل أنا و https://github.com/rust-lang-nursery/chalk تقدمًا جيدًا ، والذي ينبغي أن يعالج بعض الصعوبات الموضحة أصلاً على eddyb .)
سأل بعض الأشخاص كيف يمكنهم المساعدة: أعتقد أنه في هذه المرحلة ، سيكون من الأسهل علينا محاولة إنهاء التنفيذ الأولي ، ثم معرفة الأجزاء التي تحتاج إلى الاهتمام. بمجرد أن يصبح الأمر جاهزًا ، سنحتاج إلى الكثير من الاختبارات ، باستخدام أدوات إنشاء الصور العامة في أماكن مختلفة (بما في ذلك الاختبارات غير الصالحة ، لرسائل الخطأ) ، لذلك هذا بالتأكيد مكان يمكننا القيام به بالكثير من المساعدة! سنخبرك عندما يحدث ذلك!
آسف إذا لم يكن هذا هو المكان المناسب لذلك ، لكن لدي اقتراح بخصوص المساواة في التعبيرات التركيبية المجردة. بشكل عام ، فإنه يقلل بشكل مباشر من الكتابة التابعة بالكامل والأراضي غير القابلة للتقرير. ومع ذلك ، في حالة الصدأ ، يتم إنشاء مثيل لكل شيء في النهاية بقيم / أنواع محددة ، لذلك يمكننا تأكيد بعض المساواة وتأجيل فحصها إلى حالات أحادية الشكل.
ما أعنيه هو أن طريقة بسيطة نسبيًا للتحقق من تساوي التعبيرات التركيبية المجردة هي كالتالي:
N+1 == N+1
خارج الصندوق)N+M == M+N
(ربما في عبارة where
؟). يمكن استخدام هذه المعادلات عن طريق فحص المساواة (باستخدام شكل من أشكال إغلاق التطابق). تعريف لا يكتب التحقق باستخدام هذه المعادلات المقدمة مرفوض.false
، فقد يكون هناك خطأ في التجميع ("المعادلات هي بديهيات") أو لا يمكن إنشاء مثيل لها ("المعادلات هي قيود")f
حدّدتها N
حيث N+0==N
، يجب ألا تضيع هذه المعادلة في المتصل g
لأنه سيتعين فحصه في كل مكان أحادي الشكل حيث يتم استدعاء g
.محاسن هذه الطريقة هي أنه لا توجد حاجة لمبرهن نظري ، أو محلل SMT ، أو إعادة كتابة حسابية في لغة Rustc نفسها. "فقط" تحقق من المساواة النحوية للأنواع والأسماء المستعارة للوحدات النمطية ومجموعة المعادلات التي يوفرها المستخدم.
العيوب هي أنه يدوي أكثر للمستخدم حيث يجب إضافة مساواة واضحة على ما يبدو مثل M+N=N+M
بشكل صريح.
/// this works directly because of syntactic checks
fn add_end<T:Copy, const N: usize>(a: &[T;N], b: T) -> [T;N+1] {
let x : [T;N+1] = [b;N+1];
x[0..N] = a;
x
}
/// this should work already
fn append<T:Copy, const M:usize, const N:usize>(a: &[T;M], b: &[T;N])
-> [T;{M+N}]
{ … }
/// Here the equation M+M==N must be carried over or checked whenever this function is used
fn sum_pairwise_append<const M: usize, const N: usize>(a: &[i32, M],b: &[i32;N])-> [T;N]
where M+M == N {
let mut res : [i32; N] = append(a,a);
for i in 0 .. N { res[i] += b[i] };
res
}
fn main() {
let a: [i32; 2] = [1;2];
let b: [i32; 4] = [2;4];
let _ = sum_pairwise_append(a, b); // need to check 2+2=4
}
هذا يعني أن e1 == e2
يجب أن يكون دائمًا صحيحًا ، لذا فهو ليس قيدًا where
ولكنه يشبه إلى حد كبير assert_eq!(e1,e2)
الذي يمكن استخدامه بواسطة مدقق النوع. هنا يقدم المنفذ وعدًا بأن هذا صحيح دائمًا ، ويعرض مستخدميه لأخطاء التجميع إذا قدموا معلمة تدحض المعادلة.
هنا شرط where e1 == e2
هو قيد يجب استيفاؤه من أجل الاستخدام الناجح لهذه السمة / الوظيفة ذات المعلمات. هذا يعني أن e1 == e2
ليس مضطرًا إلى الاحتفاظ به دائمًا ، وهو ما قد يكون مثيرًا للاهتمام بالنسبة للمعادلات التي تنطبق فقط على النطاق ، مثل (x*y) / z == (y*x) / z
الذي قد يفشل في إنشاء مثيل لـ z==0
.
@ c-cube لدينا بالفعل نظام لـ "عبارات ضمنية where
" ، على الأقل للوظائف ، مشتقة من قواعد " WF
(شكل جيد)" ، أي إذا حددت fn foo<'a, 'b>(x: &'a &'b i32) {}
ثم يتطلب من المتصلين إرضاء 'b: 'a
(كنتيجة للحاجة إلى WF(&'a &'b i32)
-> &'b i32: 'a
-> 'b: 'a
).
يمكننا إعادة استخدام هذا النظام (في الواقع تم تنفيذه بالفعل) لدفع القيود التي يوفرها التوقيع (للنموذج "يتم تقييم هذا التعبير الثابت بنجاح") وصولاً إلى المتصلين ، في حين أن أي شيء يستخدم داخل الجسم فقط سيظل بحاجة إلى where
جمل
يبدو أن معظم كل شيء آخر تصفه قريبًا مما هو مخطط له (بما في ذلك شكل من أشكال "المساواة النحوية") ، لكننا لا نريد عمليات تحقق "monomorphization-time" ، يمكننا بدلاً من ذلك الحصول على طرق (إما ضمنيًا أو من خلال where
عبارات أو بخلاف ذلك إذا كان بإمكاننا تقييمها ولم تصادفها.
يبدو أن معظم كل شيء آخر تصفه قريبًا مما هو مخطط له
eddyb هل تعرف أي
@ flip111 على الأرجح بعض طلبات التعليقات. ربما يعرف withoutboats أفضل.
# 51880 انتهى: تادا :: تادا:
withoutboats @ oli-obk ما رأيك في منع التوحيد الصحيح لتعبيرات مثل N + 1
(من على سبيل المثال [T; N + 1]
) للحصول على شكل أساسي من التقييم الرمزي في miri
؟
أعتقد أنه كان لدينا بالفعل آلية لتشفيرها ، عندما يضيف ConstValue::{Infer,Param}
، يمكننا استخدام ذلك لتتبع قيم "(رمزية) (سطحية) صالحة ولكن غير معروفة" ، ثم تضمين القيمة أيضًا (بشكل أساسي) أعداد صحيحة) وعمليات مكالمات فوق ذلك.
أي قرارات بخلاف assert
التحكم في التدفق ستتطلب قيمًا معروفة ، ولكن ربما يمكن إعادة تعيين assert
نفسه على أنه AssertThen(condition, assert message, success value)
.
(يمكن أن يكون كل من condition
و success value
رمزًا!)
القدرة على تصدير القيم الرمزية إلى ty::Const
تعني أنه يمكننا تنفيذ بعض التوحيد خارج ميري ، مع معاملة (معظم؟) العمليات على أنها مبهمة.
يجب أن نكون حريصين على عدم افتراض أي شيء من متغيرات الاستدلال ، ولكن على سبيل المثال N + 1
أعتقد أنه يمكننا دعم توحيد اثنين Add(Param(N), Bits(1))
معًا.
varkor حالة اختبار أعتقد أنها يجب أن تعمل مع التطبيع
/*const*/ fn append<const N: usize, T>(xs: [T; N - 1], x: T) -> [T; N] {
let new = MaybeUninit::<[T; N]>::uninitialized();
unsafe {
let p = new.as_mut_ptr() as *mut T;
(p as *mut _).write(xs);
p.add(N - 1).write(x);
}
new.into_inner()
}
هذا من شأنه أن يعمل فقط للأسباب التالية:
N - 1
على مستوى النوع مرة واحدة بالضبطtype ArrayWithoutLast<T, const N: usize> = [T; N - 1];
)N
ArrayWithoutLast
where
" مثل [T; N - 1]: Sized
where [T; N - 1]:
(هل يتم تجاهل ذلك اليوم؟ ouch!)where ArrayWithoutLast<T, N>: ...
لذا بشكل عام ، يمكننا على الأرجح الاعتماد على قواعد WF لفرض "التحقق من صحة" تعبيرات const على المستخدمين ، لكننا ما زلنا نريد التوحيد لأشياء أخرى (بما في ذلك عدم الحاجة إلى اختراق مثل ArrayWithoutLast
).
سؤال صغير ينشأ من مناقشة وحدات القياس. ماذا يجب أن نفعل إذا كان النوع العام على الثابت لا يعتمد عليه بشكل مباشر؟ على سبيل المثال:
struct Foo<T, const N: usize> {
a: T,
// Will such array be "the way" to handle this problem?
// Or do we want some kind of `std:marker::PhantomConstData`? (which can be a simple
// type alias to the same array)
// Or maybe make `PhantomData` to accept constants?
_phantom: [(), N],
}
_phantom: [() ، N] ،
أفترض أنك كنت تقصد [(); N]
، لكن هذا لن يعمل إلا مقابل usize
.
أعتقد أنه سيكون من المنطقي أن يكون لديك marker::PhantomConst
يسمح بأي نوع const
.
حسنًا ... إعادة قراءة طلب التعليقات مع أخذ التعليقات الأخيرة في الاعتبار ، أتساءل: هل يُسمح بشيء كهذا؟
struct Foo<T, const V: T> {
_phantom: PhantomConst<T, V>,
}
لا أستطيع أن أرى أنه تم حظره في أي مكان ، لكني كنت أعتقد أنه يستحق مثالاً على الأقل.
Ekleog : على حد
كيف يتم التقدم في هذا؟ هل نعرف وقتًا تقريبيًا يجب أن يحدث هذا كل ليلة؟
Zauberklavier بمجرد الانتهاء من طلب السحب هذا . اقتبس منه:
هناك طريق طويل لنقطعه
newpavlov افترضت أنه سيتم السماح بالمعلمات الثابتة دون استخدامها في الحقول.
يجب استخدام معلمات نوع السبب بسبب التباين ، لكن الثوابت لا تحتوي على هذه المشكلة.
eddyb هذا ما أذكره من مناقشة RFC أيضًا.
varkor هذا يعني أن PhantomConst
اقترحه cuviper لا يمكن أن يوجد في الحالة الحالية لـ RFC ... أليس كذلك؟ على الرغم من أن التعليقات الأخيرة تشير إلى أنه لا توجد حاجة لـ PhantomConst
أي حال.
هل تؤثر معاملات const على تباين معلمات النوع التي تتضمنها؟
أعتقد حاليًا أنه لا يمكن أن تحتوي الأدوية العامة الثابتة على معلمات نوع في نوعها.
لست واضحًا بشأن ما يمكن أن تفعله النسخة الأولى العاملة من هذا.
على سبيل المثال ، ما إذا كانت الشفرة في هذا التعليق ستجمع:
https://github.com/rust-lang/rfcs/pull/2581#discussion_r230043717
إذا تم تجميع هذه الشفرة ، فستكون طريقة لفرض قيود على الثوابت قبل الحصول على صيغة لها.
@ rodrimati1992 يمكنك على الأرجح عمل (): IsTrue<{N < 128}>
بدون نوع منفصل.
أعتقد أنك تريد إعادة استخدام القيد وهل يعمل بالفعل؟ (لأن نسخ التعبير N < 128
لن ينجح في البداية)
أعتقد أنه يمكنك استخدام trait Lt128<const N: usize> = IsTrue<{N < 128}>;
.
هناك أيضًا خيار كتابة where [(); 128 - N],
، على ما أعتقد (لكنني لست متأكدًا من أننا نضمن أن ذلك سيؤدي إلى الذعر).
@ rodrimati1992 يمكنك على الأرجح عمل
(): IsTrue<{N < 128}>
بدون نوع منفصل.
أعتقد أنك تريد إعادة استخدام القيد وهل يعمل بالفعل؟ (لأن نسخ التعبيرN < 128
لن ينجح في البداية)
أعتقد أنه يمكنك استخدامtrait Lt128<const N: usize> = IsTrue<{N < 128}>;
.
هناك أيضًا خيار كتابةwhere [(); 128 - N],
، على ما أعتقد (لكنني لست متأكدًا من أننا نضمن أن ذلك سيؤدي إلى الذعر).
لذا ، باستخدام الأسماء المستعارة للسمات التي يمكنني إعادة كتابتها هل هذا ؟:
trait AssertLessThan128<const N:usize>=
Assert<{N<=128}, (
Str<"uint cannot be constructed with a size larger than 128,the passed size is:",
Usize<N>>
) >;
الفكرة مع Assert
(Str<"uint cannot be constructed with a size larger than 128,the passed size is:",Usize<N>>)
والذي أتوقع أن يكون أكثر فائدة من where [(); 128 - N],
، لأنه يخبرك في رسالة الخطأ عن سبب حدوث خطأ وقت الترجمة.
يمكنك أيضًا القيام بـ if !(N < 128) { panic!("...") }
بشكل ثابت ، على ما أعتقد؟
اعتقدت أن بنية std :: fmt لن تكون موجودة حتى const trait
قيود
مع هذا الشيء يمكن أن يكون لديك رسائل خطأ بقيم متعددة فيه (مضمنة في الأنواع).
ربما يكون من الأفضل الانتظار حتى تتحدث أنواع ثابتة عن هذا الأمر ، لأنه سيكون من الأسهل عرض أمثلة قابلة للتنفيذ.
@ rodrimati1992 انظر https://github.com/rust-lang/rfcs/blob/master/text/2345-const-panic.md ، ستكون هناك حالة خاصة للحصول على panic!()
قبل أن تحصل عليها أن يكون ممكنًا عبر ميزات أخرى (على الأرجح لن يسمح بالتنسيق المخصص للقيم في البداية).
@ rodrimati1992 آه ، أرى أن هذه خدعة ذكية حقًا!
ما هي حالة هذا؟
الخطوة التالية لا تزال https://github.com/rust-lang/rust/pull/53645 AFAIK.
هذا صحيح. لإعطاء تحديث سريع لأولئك الذين لا يتبعون PR # 53645 ، تم تجميع ملفات const Genics والعمل في حالة استخدام واحدة بسيطة على الأقل. ما تبقى هو الانتهاء من codegen لحالات استخدام أخرى ، بما في ذلك العوامل الثابتة في arrys ، وبعض تنظيف إخراج الأخطاء. بعد ذلك ، يجب أن تكون العلاقات العامة جاهزة للدمج ويمكن للأشخاص البدء في اللعب بها.
قد يكون خارج الموضوع ، لكن هل سيسمح ذلك لمتغير أو تفرع من القطع والطرق ذات الصلة بأن يكون Item
مصفوفة ذات حجم ثابت للترجمة بدلاً من شريحة؟ سيسمح هذا لحلقة for
بالتدمير / الارتباط بنمط لا يمكن دحضه يقوم بتعيين العناصر في القطعة إلى متغيرات ، مثل for (first, second) in arr.chunks(2)
الذي فشل حاليًا ، وأنا أخمن (بدون أي مبرر باعتراف الجميع) أنه سيسمح بمزيد من التحسين في حالات استخدام معينة.
jeffvandyke ربما تفكر في ChunksExact على وجه التحديد. سيكون مثل هذا التغيير كسرًا لواجهة برمجة التطبيقات ، لذا لا يمكن القيام به. يمكننا إضافة واجهات برمجة تطبيقات جديدة تقدم مراجع مصفوفة في المستقبل ، لكن لا يمكننا كسر الموجود منها.
jeffvandyke ربما تفكر في ChunksExact على وجه التحديد. سيكون مثل هذا التغيير كسرًا لواجهة برمجة التطبيقات ، لذا لا يمكن القيام به. يمكننا إضافة واجهات برمجة تطبيقات جديدة تقدم مراجع مصفوفة في المستقبل ، لكن لا يمكننا كسر الموجود منها.
أنا فقط في انتظار تنفيذ هذا واستقراره قبل اقتراح العلاقات العامة التي تضيف واجهة برمجة التطبيقات هذه بالإضافة إلى ChunksExact
ومتغيراتها :)
لكل من متغيرات وقت التشغيل ووقت الترجمة حالات الاستخدام الخاصة بهم ، فأنت لا تعرف دائمًا حجم الجزء الخاص بك مسبقًا. من ناحية التحسين ، إذا كنت تستخدم ChunksExact
مع ثابت ، فيجب أن تكون متشابهة إلى حد ما وفقًا للاختبار الذي أجريته. يمكن للمجمع تحسين جميع عمليات التحقق من الحدود.
ليتم تنفيذها واستقرارها
أنا أقترح لا تنتظر لتحقيق الاستقرار على هذا النحو لAPI سيكون واحدا الاستخدام الجيد لمساعدة ممارسة هذه الميزة لتحقيق الاستقرار.
أظن أن هذا لا يعمل حتى الآن مع كتل impl
؟ حاولت
#![feature(const_generics)]
struct The<const Val: u64>();
impl<const Val: u64> The<Val> {
fn the() {
println!("{}", Val);
}
}
ولكن ، كما تم تحذيره بالفعل ، تعطل المترجم مع
thread 'rustc' panicked at 'slice index starts at 1 but ends at 0', src/libcore/slice/mod.rs:2419:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
1: std::sys_common::backtrace::_print
2: std::panicking::default_hook::{{closure}}
3: std::panicking::default_hook
4: rustc::util::common::panic_hook
5: std::panicking::rust_panic_with_hook
6: std::panicking::continue_panic_fmt
7: rust_begin_unwind
8: core::panicking::panic_fmt
9: core::slice::slice_index_order_fail
10: rustc_resolve::Resolver::resolve_ident_in_lexical_scope
11: rustc_resolve::Resolver::resolve_path
12: rustc_resolve::Resolver::resolve_path_without_parent_scope
13: rustc_resolve::Resolver::smart_resolve_path_fragment
14: rustc_resolve::Resolver::smart_resolve_path
15: <rustc_resolve::Resolver<'a> as syntax::visit::Visitor<'tcx>>::visit_ty
16: syntax::visit::walk_generic_args
17: syntax::visit::walk_ty
18: rustc_resolve::Resolver::with_generic_param_rib
19: rustc_resolve::Resolver::resolve_item
20: rustc_resolve::Resolver::resolve_crate
21: rustc::util::common::time
22: rustc_interface::passes::configure_and_expand_inner
23: rustc_interface::passes::configure_and_expand::{{closure}}
24: <rustc_data_structures::box_region::PinnedGenerator<I, A, R>>::new
25: rustc_interface::passes::configure_and_expand
26: <rustc_interface::queries::Query<T>>::compute
27: <rustc_interface::queries::Query<T>>::compute
28: <rustc_interface::queries::Query<T>>::compute
29: rustc_interface::queries::<impl rustc_interface::interface::Compiler>::prepare_outputs
30: rustc_interface::interface::run_compiler_in_existing_thread_pool
31: <std::thread::local::LocalKey<T>>::with
32: <scoped_tls::ScopedKey<T>>::set
33: syntax::with_globals
الخطأ متعلق بـ const
في impl<const Val: u64>
حيث أن إزالة هذا الجزء تسبب أخطاء أخرى ولكن لا يحدث عطل.
لكن الدعائم ل Rust حتى حتى النظر في هذه الميزة. لم يكن لدي أي فكرة عما إذا كانت ستنجح ولكن بناء الجملة بدا طبيعيًا ، لقد ذهبت من أجله ، وقال لو rustc إنه موجود :)
لست مندهشًا من أنها لا تعمل ، لأن هذه الميزة التي تم توقعها بشدة لا تزال قيد التشغيل من خلال المترجم كما نتحدث (انظر على سبيل المثال # 59008 و # 58581 والعمل السابق على # 53645 الذي تم التخلي عنه لأن العلاقات العامة كانت كبيرة جدًا ، ولكن لا يزال مفتوحًا كمتعقب للإعلان عن التقدم).
ومع ذلك ، لست متأكدًا مما إذا كان يجب توقع وصول الشرائح خارج الحدود من خطوات التنفيذ الحالية. varkoryodaldevoid، يمكنك إلقاء نظرة؟
نعم ، التحذير صحيح: لا تعمل الأدوية الثابتة بعد بأي شكل من الأشكال. لا يزال هناك عدد قليل من طلبات السحب قبل أن يكونوا جاهزين لبدء اللعب بها.
آسف إذا لم يكن هذا هو المكان المناسب لطرح الأسئلة ولكن لم أجد أي مكان أفضل منه. سؤالان فقط:
هل يمكن أن تكون دالة واحدة ثابتة شرطية ؟ على سبيل المثال ، يمكن أن تحتوي الوظيفة على توقيعين مثل:
const fn foo<A: const T>(x: T) // `A` const implements `T`
fn foo<A: T>(x: A) // `A` implements `T` normally
في هذه الحالة ، foo
هو ثابت iff A: const T
؛ إذا كان A
لا يطبق T
، فإنه لا يزال يفي بالحد ولكن foo
لم يعد ثابتًا. من المهم أيضًا أن يكون المؤلف قادرًا على تحديد أي حد عام لأمثلة أكثر تعقيدًا (على سبيل المثال where A::Output : Bar
). ومن الأمثلة الرائعة على ذلك عملية حسابية بسيطة:
// This only accepts types that const implement `T`
const fn square_const<T: const Mul>(x: T) -> T {
x*x
}
// This accepts types that implement `T` any way, but it is not const
// This function behaves identically to `square_const`
// But has a different signature and needs a different name
fn square<T: Mul>(x: T) -> T {
square_const(x)
}
let a: u8 = 5;
let b: FooNumber = FooNumber::new();
square_const(a); // `u8` const implements Mul
square(b); // `FooNumber` implements `Mul` normally, so we need a separate function?
أشعر بقوة أنه يجب أن تكون هناك بالتأكيد طريقة للقيام بذلك ، وأنا مندهش من عدم ذكرها في RFC (إلا إذا فاتني ذلك؟).
_ [أقل أهمية]: _ هل ستكون هناك طريقة للكشف في جسم دالة ثابتة سواء كنا نعمل في وقت التجميع أو وقت التشغيل؟ أعتقد أن بعض وحدات الماكرو المشابهة لـ cfg!()
ستكون امتدادًا مفيدًا ، إذا لم يكن هناك سبب آخر غير التصحيح. cfg!()
حاليًا في وقت الترجمة بالفعل ، لذلك أعتقد (/ تخمين) أنه يجب أن يكون قادرًا على معرفة ما إذا كان يتم استخدام الوظيفة كدالة ثابتة أم لا حيث يتم تحديد ذلك أيضًا عند التجميع -زمن. لكن هذا أقل أهمية من سؤالي الأول.
@ المبرمج 256
@ Coder-256 كلا هذين السؤالين لا علاقة لهما بعلم الثوابت ، بل بالأحرى دوال ثابته. تستخدم الأدوية العامة للأرقام الثابتة لكونها عامة أكثر من الثوابت (على سبيل المثال foo<2>()
) بدلاً من الوظائف التي يمكن تشغيلها في وقت الترجمة. أتخيل أن هذا هو السبب في أنك لم تجد إجابات لأسئلتك في RFC 2000.
rpjohnst شكرًا لك ، لكني أعتقد أنني قد أكون غير واضح. لقد رأيت بالفعل كلا من rust-lang / rfcs # 2632 و rust-lang / rfcs # 2000 ، لكنني متأكد من أن هذا لم يرد في أي منهما. (ولكن قد أكون مخطئا؟) ما أسأل عنه هو دوال شرطية . انظر إلى الأمثلة التي كتبتها لأنه من الصعب وصفها.
yodaldevoid عفوًا ، أنت على حق ، أين أسأل هذا؟
بالنسبة لسؤال الماكرو ، أوافق على أنه لا يوجد فائدة كبيرة له الآن بعد أن أفكر فيه
ما أسأل عنه هو دوال شرطية. انظر إلى الأمثلة التي كتبتها لأنه من الصعب وصفها.
يمكن استخدام تعريف square_const
بدلاً من square
(أي: يتم إجباره على وظيفة بالتوقيع المكافئ في وقت التشغيل). راجع https://github.com/rust-lang/rfcs/pull/2632 لمناقشة هذا السلوك (أيضًا ، هذا الخيط هو المكان المناسب لطرح أسئلة حول أي تفاعلات بين const fn
وحدود السمات).
varkor لست مقتنعًا بأن هذا هو الحال (منذ تغير حدود السمات) ، لكنني سأطلب في rust-lang / rfcs # 2632.
تقرير الأعطال:
الشفرة:
#![feature(const_generics)]
use std::marker::PhantomData;
struct BoundedU32<const LOWER: u32, const UPPER: u32> {
value: u32,
_marker: PhantomData<(LOWER, UPPER)>,
}
مترجم:
thread 'rustc' panicked at 'slice index starts at 1 but ends at 0', src/libcore/slice/mod.rs:2419:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: rustc 1.35.0-nightly (719b0d984 2019-03-13) running on x86_64-unknown-linux-gnu
note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type lib
note: some of the compiler flags provided by cargo are hidden
error: Could not compile `playground`.
To learn more, run the command again with --verbose.
Jezza : إن Generator لم تنفذ بالكامل بعد ولا يُتوقع أن تعمل. سنصدر إعلانًا عندما يحين وقت بدء تجربة #![feature(const_generics)]
(والذي سيتم إعلامك به إذا كنت مشتركًا في هذه المشكلة).
varkor معلقة على، سبيل المثالJezza الصورة لديها _marker: PhantomData<(LOWER, UPPER)>
- تلك نوعان const
المعلمات تستخدم أنواع، لماذا لم rustc_resolve
ينتج خطأ؟
نقطة جيدة: سأحقق في هذا. لاحظ أن هذه مشكلة فقط مع #![feature(const_generics)]
، لذا فهي ليست مشكلة حرجة (استخدام الثوابت غير العامة ينتج الخطأ كما هو متوقع). ربما لا تصل أبدًا إلى rustc_resolve
.
~ eddyb : resolve_ident_in_lexical_scope
، لذلك أتخيل أنه من المحتمل أن يكون مرتبطًا بـ https://github.com/rust-lang/rust/issues/58307.~
تحرير: في الواقع ، ربما لا - يبدو أنه ينطبق فقط على macro_rules!
.
مصغر:
#![feature(const_generics)]
struct S<const C: u8>(C);
قم بحل ICE قبل إنتاج الخطأ "النوع المتوقع ، القيمة التي تم العثور عليها".
الفهرس خارج الحدود هنا:
https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/lib.rs#L3919
تنتج الليلة الحالية "المعلمة N
لم يتم استخدامها أبدًا" للرمز التالي:
struct Foo<const N: usize> { }
من المناقشة السابقة اعتقدت أن التجميع يجب أن يقبل هذا الرمز. هل هو مجرد قطعة أثرية من التنفيذ غير المكتمل؟
newpavlov يجب استخدام معلمات النوع العادي ، PhantomData<n>
؟
أعتقد أنه من الممكن بالفعل القيام بـ PhantomData<[(); N]>
. لست متأكدًا من أن هذا شيء نريد حقًا فرضه ، على الرغم من ذلك ، مثل AFAIU ، فإن النقطة PhantomData
هي تحديد التباين ، ولا يوجد AFAIU أي فكرة عن التباين مكتوب. معلمة عامة ثابتة.
وهذا لا يعمل إلا عندما يكون N من النوع usize
.
لقد قررنا أنه ليس من الضروري استخدام معلمات const أثناء مناقشة RFC والتنفيذ الحالي هو خطأ.
withoutboats هل يمكنك الإشارة إلى مكان ما ورد في RFC؟ حاولت العثور على شيء بهذا المعنى ويجب أن يكون قد فاتني.
لا أعرف ما إذا كان قد تم تضمينه في نص RFC
withoutboats هل تمانع في الإشارة إلى مكان مناقشة ذلك؟ بحثت في RFC PR ، لكنها لم تقفز في وجهي.
yodaldevoid تمت الإشارة إلى هذا التعليق سابقًا: https://github.com/rust-lang/rust/issues/44580#issuecomment -419576947. لكنه لم يكن في RFC PR ، بل كان في هذه القضية.
لا يمكنني البحث في سجل التعليقات منذ عدة سنوات الآن ، ولكن يمكنني أن أشرح: استخدام متغيرات النوع مطلوب كحاجز لتجعلك تفكر في تباين هذه المعلمات (IMO هذا أيضًا غير ضروري ويمكننا افتراضيًا إلى المتغير المشترك ، لكن هذه قضية منفصلة). لا تحتوي معاملات Const على أي تفاعل مع التباين ، لذلك لن يكون لهذا دافع.
@ HadrienG2 شكرًا لك على العثور على تعليق ذي صلة.
withoutboats لم أكن أتوقع حقًا أن تذهب للبحث في كل سنوات التعليقات على هذا ، كان مجرد أمل في أن يكون لديك بالفعل في متناول اليد.
شكرا لك على التفسير. يجب أن أعترف أنه لا يمكنني أبدًا أن ألتف ذهني حول التباين بغض النظر عن عدد المرات التي أحاول أن أتعلمها ، ولكن حتى بدون ذلك عندما يكون التفكير مرة أخرى لا يتطلب استخدام معلمات التكلفة أمرًا منطقيًا. سأقوم بإصلاح هذا الخطأ في قائمة FIXMEs الخاصة بنا.
فيما يلي ملخص للتقدم المحرز حتى الآن في الأدوية العامة.
قبل أن يبدأ العمل على الأدوية العامة الثابتة بشكل صحيح ، كان هناك بعض إعادة الهيكلة التي يجب القيام بها. تولى jplatte المهمة مع https://github.com/rust-lang/rust/pull/45930. بعد ذلك ، بدأ jplatte العمل على التطبيق الرئيسي للأدوية الثابتة ، لكنه اكتشف أنه لم يكن لديه الوقت الكافي للمتابعة.
التقطت أنا و yodaldevoid المكان الذي توقفت فيه https://github.com/rust-lang/rust/pull/48149 ، https://github.com/rust-lang/rust/pull / 48452 ، https://github.com/rust-lang/rust/pull/48523 ، https://github.com/rust-lang/rust/pull/51880.
مع القيام بذلك ، يمكن أن يبدأ تطبيق الأدوية العامة بجدية. منذ ذلك الحين ، عملت أنا و https://github.com/rust-lang/rust/pull/58191 ، https://github.com/rust-lang/rust / pull / 58503 ، https://github.com/rust-lang/rust/pull/58581 ، https://github.com/rust-lang/rust/pull/58583 ، https://github.com/rust -lang / rust / pull / 59170 ، https://github.com/rust-lang/rust/pull/59355 ، https://github.com/rust-lang/rust/pull/59415 ، https: // github .com / rust-lang / rust / pull / 60058 ، https://github.com/rust-lang/rust/pull/60280 ، https://github.com/rust-lang/rust/pull/60284 and most مؤخرًا https://github.com/rust-lang/rust/pull/59008. (تم فصل هذه في الغالب عن
ما هو الوضع الآن؟ تعمل بعض الاختبارات العامة لـ const ومع ذلك ، لا تزال هناك اختبارات لا تعمل ، وهناك عدد من FIXME
s في جميع أنحاء الكود الذي لا يزال يتعين علينا معالجته. نحن نقترب الآن ، رغم ذلك ، ونحن في مرحلة حيث توجد بعض الفاكهة المتدلية إذا كنت تريد المساعدة.
FIXME(const_generics)
منتشر في جميع أنحاء الكود. نحن نخطط للعمل في طريقنا من خلالها ، لكن yodaldevoid ولدي الكثير من الوقت فقط ، لذلك إذا كنت تعتقد أنه يمكنك معالجة واحدة ، لقد قمت بكتابة نظرة عامة على بعض مشكلات التنفيذ المتبقية قبل أن تصبح أدوات const Genics جاهزة للاختبار المناسب ، في المنشور العلوي ، لإعطاء فكرة تقريبية عما تبقى للقيام به.
لقد استغرق الأمر وقتًا ، لكننا نحقق تقدمًا مطردًا ونأمل في مواكبة الوتيرة. إنه لأمر محفز أن ترى أخيرًا الأشياء بدأت في الظهور!
لقد كنت أتوقع شهورًا لهذا المنشورvarkor :) أنا لست معالج الصدأ ولكني أود التعامل مع أحد FIXME
s
تهانينا jplatte و yodaldevoid وvarkor. هذه خطوة كبيرة للتخلص من السمات المخصصة Array-like
في مراسيم الرياضيات.
عبر نشر...
varkor فيما يتعلق بالاختبارات ، ربما يكون من المفيد معرفة ما هو متوقع أن يعمل. على سبيل المثال ، فوجئت أن هذا لا يعمل: https://play.rust-lang.org/؟version=nightly&mode=debug&edition=2018&gist=d84ffd15226fcffe02c102edb8ae5cf1
أيضًا ، كمرجع للمهتمين بـ FIXMEs: https://oli-obk.github.io/fixmeh/
@ mark-im حاول وضع {}
حدود FOO
. بهذه الطريقة ستعمل.
نقلاً عن https://github.com/rust-lang/rfcs/blob/master/text/2000-const-generics.md :
عند تطبيق تعبير كمعامل ثابت (باستثناء المصفوفات) ، وهو ليس تعبير هوية ، يجب احتواء التعبير داخل كتلة. هذا التقييد النحوي ضروري لتجنب طلب نظرة غير محدودة عند تحليل تعبير داخل نوع ما.
يجب أن يكون {expression}
ضروريًا فقط إذا لم يكن التعبير معرّفًا أو حرفيًا ، فهذا خطأ.
نقلا عن نفس RFC:
تعبير الهوية: تعبير لا يمكن تقييمه بشكل أكبر إلا باستبداله بأسماء في النطاق. يتضمن هذا كل العناصر الحرفية وكذلك جميع المعرفات - على سبيل المثال 3 ، "مرحبًا ، العالم" ، foo_bar.
@ mark-im نعم ، حاليًا لا يمكننا التمييز بين معرفات الأنواع والثوابت عند التحليل المبدئي. لقد قررنا اتخاذ القرار بشأن كيفية التعامل مع كل ذلك في المستقبل. أفترض الآن قد يكون المستقبل.
للحصول على خلفية صغيرة ، تحدثنا عن طريقتين يمكنني تذكرهما حول كيفية التعامل مع هذا. الطريقة الأولى هي إجبار الأشخاص على وضع علامة على وسيطات ثابتة (إما بكتابة const
قبلهم أو بطريقة أخرى). هذا ليس رائعًا من وجهة نظر بيئة العمل ، ولكنه سهل من وجهة نظر التحليل. الطريقة الثانية هي التعامل مع جميع الحجج العامة كما هي حتى نبدأ في إقرانها بالمعلمات العامة لاحقًا أثناء التجميع. ربما تكون هذه هي الطريقة التي نريد اتباعها ، وكان هناك بعض العمل لجعل هذا ممكنًا بالفعل ، ولم نتخذ القفزة النهائية.
عمل مدهش. يسعدني تقديم المساعدة ، من خلال إصلاح بعض من FIXME
، إذا كان بإمكاني. ليس لدي الكثير من الخبرة داخل قاعدة بيانات rustc على الإطلاق ، لذلك سأبدأ في FIXME https://github.com/rust-lang/rust/blob/master/src/librustc_mir/monomorphize/item.rs# L397 ، كما يبدو أنه سيكون سهلًا.
ماذا عن الكود التالي:
trait Foo {
const N: usize;
fn foo() -> [u8; Self::N];
}
حاليًا ينتج عنه "عدم وجود عنصر مرتبط باسم N
للنوع Self
في النطاق الحالي" خطأ تجميع. هل سيتم قبول هذا الرمز بعد الانتهاء من FIXME
s أم أنه سيتطلب جهدًا إضافيًا لتنفيذه؟
تضمين التغريدة
سؤال سريع ، معذرة إذا كان هذا قد تمت مناقشته بالفعل.
الطريقة الثانية هي التعامل مع جميع الحجج العامة كما هي حتى نبدأ في إقرانها بالمعلمات العامة لاحقًا أثناء التجميع. ربما تكون هذه هي الطريقة التي نريد اتباعها ، وكان هناك بعض العمل لجعل هذا ممكنًا بالفعل ، ولم نتخذ القفزة النهائية.
ألا يتعارض هذا مع الاتجاه الصحيح وفقًا للمبدأ الذي يأخذه Rust في جعل توقيعات الوظيفة صريحة لتجنب حدوث أخطاء تتعلق بتنفيذ الوظيفة؟ ربما أسيء فهم هذا تمامًا وأنت تتحدث عن تحليل المعلمات العامة داخل جسم الوظيفة.
ألا يتعارض هذا مع الاتجاه الصحيح وفقًا للمبدأ الذي يأخذه Rust في جعل توقيعات الوظيفة صريحة لتجنب حدوث أخطاء تتعلق بتنفيذ الوظيفة؟ ربما أسيء فهم هذا تمامًا وأنت تتحدث عن تحليل المعلمات العامة داخل جسم الوظيفة.
يتعلق الأمر بتحديد ما إذا كانت المعرفات التي تم تمريرها كمعلمات عامة إلى دالة هي ثوابت أم أنواع.
مثال:
fn greet<const NAME:&'static str>(){
println!("Hello, {}.",NAME);
}
const HIS_NAME:&'static str="John";
greet::<HIS_NAME>();
greet::<"Dave">();
لاحظ أنه عند تحديد الوظيفة ، يجب عليك تحديد أن NAME ثابت ، ولكن عندما تسميها ، ليس من الضروري القول أن HIS_NAME ثابت داخل مشغل التوربيني ( ::< >
).
zesterer إذا تم جعل هذا الحل المقترح شفافًا للمستخدم (على سبيل المثال ، عند تحديد وظيفة لم يكن هناك فرق بين أنواع المعلمات) فستكون على صواب. ومع ذلك ، فإن الفكرة وراء الحل المقترح ليست تغيير سلوك مواجهة المستخدم ، بل تغيير التنفيذ فقط. سيظل المستخدم يكتب تواقيع الوظيفة مع معلمات النوع الصريح ، والثابت ، ومعلمات العمر ، وستظل الوسيطات العامة بحاجة إلى المطابقة مع المعلمة المقابلة ، فقط كيف يمكننا تحليلها في المترجم سيتغير.
newpavlov أنا مندهش من أن الكود لا يعمل. إذا كان بإمكانك إرسال قضية منفصلة ، فسيكون موضع تقدير.
تضمين التغريدة
آه ، فهمتك. افترضت خطأً أن هذا يتعلق بتوقيعات النوع / الوظيفة.
لاستخدام العوامل الثابتة على أنواع المصفوفات المضمنة ، فتحت # 60466 لمشاهدة آراء الآخرين حول هذا الموضوع.
تبدو كتل Impl مكسورة تمامًا في الوقت الحالي. هل هذا متوقع في الحالة الحالية للميزة ، أم يجب فتح مشكلة أخرى حولها؟
تبدو كتل Impl مكسورة تمامًا في الوقت الحالي. هل هذا متوقع في الحالة الحالية للميزة ، أم يجب فتح مشكلة أخرى حولها؟
تحتاج إلى إضافة {}
s حول N
، impl<const N: usize> Dummy<{N}> {}
.
لكن نعم ، ستحصل على خطأ بشأن المعلمة غير المقيدة.
آه بفضل. نسيت شيئا عن تقويم الأسنان!
لست مندهشًا من فشلها بمجرد حلها ، نظرًا لأن هذه كانت حالة اختبار مصغرة للغاية.
... لكن نعم ، من المحتمل أن يعمل هذا:
#![feature(const_generics)]
trait Dummy {}
struct Vector<const N: usize> {
data: [f32; N],
}
impl<const N: usize> Dummy for Vector<{N}> {}
.. ولا يزال يفشل مع E0207:
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> src/lib.rs:1:12
|
1 | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates
--> src/lib.rs:9:12
|
9 | impl<const N: usize> Dummy for Vector<{N}> {}
| ^ unconstrained const parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0207`.
error: Could not compile `small-matrix`.
To learn more, run the command again with --verbose.
... وأفترض أن هذا هو ما قصده varkor بـ "مشكلات معالجة المصفوفات الخاصة بـ consts Genics" في # 60466:
#![feature(const_generics)]
fn dummy<const N: usize>() -> [f32; N] {
[0.; N]
}
->
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> src/lib.rs:1:12
|
1 | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error: internal compiler error: cat_expr Errd
--> src/lib.rs:3:44
|
3 | pub fn dummy<const N: usize>() -> [f32; N] {
| ____________________________________________^
4 | | [0.; N]
5 | | }
| |_^
error: internal compiler error: cat_expr Errd
--> src/lib.rs:4:5
|
4 | [0.; N]
| ^^^^^^^
error: internal compiler error: QualifyAndPromoteConstants: Mir had errors
--> src/lib.rs:3:1
|
3 | / pub fn dummy<const N: usize>() -> [f32; N] {
4 | | [0.; N]
5 | | }
| |_^
error: internal compiler error: broken MIR in DefId(0/0:3 ~ small_matrix[5b35]::dummy[0]) ("return type"): bad type [type error]
--> src/lib.rs:3:1
|
3 | / pub fn dummy<const N: usize>() -> [f32; N] {
4 | | [0.; N]
5 | | }
| |_^
error: internal compiler error: broken MIR in DefId(0/0:3 ~ small_matrix[5b35]::dummy[0]) (LocalDecl { mutability: Mut, is_user_variable: None, internal: false, is_block_tail: None, ty: [type error], user_ty: UserTypeProjections { contents: [] }, name: None, source_info: SourceInfo { span: src/lib.rs:3:1: 5:2, scope: scope[0] }, visibility_scope: scope[0] }): bad type [type error]
--> src/lib.rs:3:1
|
3 | / pub fn dummy<const N: usize>() -> [f32; N] {
4 | | [0.; N]
5 | | }
| |_^
thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', src/librustc_errors/lib.rs:356:17
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: rustc 1.36.0-nightly (cfdc84a00 2019-05-07) running on x86_64-unknown-linux-gnu
note: compiler flags: -C debuginfo=2 -C incremental --crate-type lib
note: some of the compiler flags provided by cargo are hidden
تضمين التغريدة
انظر # 60619 و # 60632.
أعتقد أن هذا الكود يجب أن يبني:
https://play.rust-lang.org/؟version=nightly&mode=debug&edition=2018&gist=e45b7b5e881732ad80b7015fc2d3795c
لكنها أخطاء حاليًا:
خطأ [E0119]: عمليات التنفيذ المتعارضة للسمة std::convert::TryFrom<[type error]>
للنوع MyArray<_, _>
:
لسوء الحظ ، يعد هذا قيدًا Try{From,Into}
وليس له أي علاقة بالأدوية الثابتة. لا يمكن تنفيذها بشكل عام في كثير من الحالات: روضة الأطفال
oberien في T
هو نوع أجنبي ، ولا يُعرف ما إذا كان T: Into<Foo<T>>
يحمل أم لا.
في المثال الخاص بي ، [T؛ N] هو نوع محدد في libcore ، وهو #[fundamental]
(لا أعرف حتى ماذا يعني هذا) ، لذلك أعتقد أن محلل السمات يعرف بالفعل [T; N]: Into<MyArray<T, {N}>>
غير صحيح ، وهناك لا ينبغي أن يكون الصراع ، على ما أعتقد؟
[...] وهو
#[fundamental]
[...]
هذه هي المشكلة ، fundamental
مرتبط بالسماح لمستخدمي المصب بتعريف تطبيقات السمات عند التفافهم لنوع محلي في نوع الغلاف الأساسي. يمكنك أن ترى في هذا الملعب أن التنفيذ الخاص بك يعمل بين الأنواع غير الأساسية ، لكنه يفشل إذا تم تمييز النوع from
fundamental
(مع رسالة خطأ أفضل بكثير).
varkoryodaldevoid لذا ، انتهى بي الأمر للتو في موقف حيث S<{N == 0}>
(مع S
مع معامل const bool
و N
a const usize
) ليس S<{true}>
أو S<{false}>
في عين المترجم (بمعنى أنه لا يطبق نفس السمات مثل أي منهما) ، ولست متأكدًا مما إذا كان هذا خطأ أم القيد المتوقع للنموذج الأولي الحالي. هل يمكن أن تعطيني تجديدًا سريعًا لمنطق التوحيد الحالي؟
كمثال مصغر ، هذا ...
// Machinery for type level if-then-else
struct Test<const B: bool>;
trait IfFn<S, Z> { type Out; }
impl<S, Z> IfFn<S, Z> for Test<{true }> { type Out = S; }
impl<S, Z> IfFn<S, Z> for Test<{false}> { type Out = Z; }
// Returns an u8 if B is true, else an u16
fn should_be_ok<const B: bool>() -> <Test<{B}> as IfFn<u8, u16>>::Out {
0
}
.. ينتج الخطأ التالي:
error[E0277]: the trait bound `Test<B>: IfFn<u8, u16>` is not satisfied
--> src/lib.rs:32:1
|
32 | / fn should_be_ok<const B: bool>() -> <Test<{B}> as IfFn<u8, u16>>::Out {
33 | | 0
34 | | }
| |_^ the trait `IfFn<u8, u16>` is not implemented for `Test<B>`
|
= help: the following implementations were found:
<Test<false> as IfFn<S, Z>>
<Test<true> as IfFn<S, Z>>
لا أعرف في الواقع ، لكنني أعتقد أن المشكلة قد تكون أن المترجم ليس لديه المنطق ليقرر ما إذا كانت القيمة الحرفية 0
هي u8
أم u16
. جرب شيئًا مثل: 0u8 as _
هذا ليس كل شيء ، تظل رسالة الخطأ كما هي.
ولكن إذا كنت تريد إصدارًا لا يتضمن استدلالًا بنوع عدد صحيح ، فإليك تصغير أكثر ذكاءً:
struct Test<const B: bool>;
trait Not { const B: bool; }
impl Not for Test<{true }> { const B: bool = false; }
impl Not for Test<{false}> { const B: bool = true; }
fn should_be_ok<const B: bool>() -> bool {
<Test<{B}> as Not>::B
}
لا يزال الإخفاق بسبب عدم تنفيذ Test<{B}>
Not
.
أهلا ! لست متأكدًا حقًا مما إذا كان من المفترض أن يعمل التوحيد في قيم ثابتة أم لا ، ولكن هناك نظام توحيد جديد في الأعمال ("الطباشير") يتم العمل عليه ولكنه ليس ما يستخدمه rustc حاليًا.
لذا فإن ما تحاول القيام به _ قد_ يجب أن ينتظر حتى يصبح الطباشير جاهزًا. وحتى ذلك الحين ، لست متأكدًا من أنه سيعمل أو من المفترض أن يعمل حتى مع الطباشير.
راجع https://github.com/rust-lang/rust/issues/48049 لمعرفة التقدم.
@ HadrienG2 هل يمكنك رفع قضية منفصلة لذلك؟ لست مندهشًا تمامًا من أن هذا لا يعمل في الوقت الحالي بسبب بعض المشكلات الأخرى التي نتطلع إليها ، ولكن هذه حالة جديدة وأود تعقبها.
carado Unification يتم إجراؤه على consts أو لن ينجح أي من هذا. لا يتم حظر الأدوية العامة على الطباشير.
@ HadrienG2 بمجرد أن يكون لدينا تخصص في الأدوية العامة الثابتة ، ستتمكن من القيام بشيء مثل
struct Test<const B: bool>;
trait Not { const B: bool; }
impl<const B: bool> Not for Test<B> { const B: bool = false; }
impl Not for Test<{false}> { const B: bool = true; }
fn should_be_ok<const B: bool>() -> bool {
<Test<{B}> as Not>::B
}
ما تريد القيام به هو نوع من التحقق من الشمولية كما هو الحال بالنسبة للمطابقة الممتدة فقط إلى نظام السمات. لا أعلم أنه مذكور في أي موضوع.
yodaldevoid تم حفظه كـ https://github.com/rust-lang/rust/issues/61537 .
carado Chalk لا يتعلق بـ "بدائل أنظمة الطباعة" الفعلية ، والتي تعد واحدة منها.
أي ، لا يزال يتعين على rustc
(حتى اليوم ، نظرًا لأن Chalk مدمج جزئيًا بالفعل) تنفيذ جزء التوحيد الذي يتعامل مع الكيانات غير الشفافة لـ Chalk (مثل تعبيرين ثابتين مختلفين).
إذا طبقنا ذلك (الذي ليس لدينا أي خطط مستقبلية قريبة له ، على أي حال) ، فلن يتغير كثيرًا حتى بعد أن يستبدل Chalk نظام السمات (وهو هدفه الرئيسي وليس التوحيد).
أوه ، يا سيئة بعد ذلك! أعتقد أنني لا أعرف حقًا ما أتحدث عنه.
واحدة من الأشياء الرائعة التي يمكن أن توفرها العواميد الثابتة هي تجميع وظائف بسيطة يتم حسابها بمرور الوقت ، على سبيل المثال عاملي.
مثال:
fn factorial<const X: i32>() -> Option<i32> {
match X {
i if i < 0 => None,
0 => Some(1),
1 => Some(1),
i => Some(factorial::<i - 1>().unwrap() + i)
}
}
بقدر ما أفهم ، هناك بعض الدعم المحدود للأدوية الثابتة في الليل؟ إذا كان الأمر كذلك ، فهل هناك أي مكان أكثر تنظيماً من هذه المشكلة حيث يمكنني العثور على كيفية استخدامه وأشياء أخرى؟
يجب أن تكون وظائف @ dancojocaru2000 const
الطريقة المفضلة لحساب مستوى القيمة في وقت الترجمة ، على سبيل المثال https://play.rust-lang.org/؟version=nightly&mode=debug&edition=2018&gist=4994b7ca9cda0bfc44f5359443431378 ، والذي يحدث لا تعمل لأنها لم يتم تنفيذها بالكامل بعد. ولكن ليست الأدوية الجنيسة هي أيضًا const
.
قد يكون المقتطف الخاص بك مشكلة لأنني لست متأكدًا مما إذا كان من المفترض أن يعمل match
لوسائط const
. لقد قمت أيضًا بخلط الجمع مع الضرب في الكود ، لكن هذا لا يهم كثيرًا.
أعتقد أنه يمكنك بالفعل عمل العوامل في وقت الترجمة باستخدام ترميز Peano ، والذي يظهر غالبًا كعرض توضيحي للغات وظيفية أخرى.
تجميع الوقت يحسب وظائف بسيطة
أعتقد أن الميزة الأكثر ملاءمة ستكون const fn .
نظريًا ، ستعمل التعليمات البرمجية الخاصة بك كما هي تقريبًا
#![feature(const_generics)]
fn factorial<const X: i32>() -> Option<i32> {
match X {
i if i < 0 => None,
0 => Some(1),
1 => Some(1),
i => Some(factorial::<{X - 1}>().unwrap() + i)
}
}
fn main() {
println!("{:?}", factorial::<10>());
}
لكنها لا:
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> src/main.rs:1:12
|
1 | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error: internal compiler error: src/librustc_codegen_ssa/mir/operand.rs:79: unevaluated constant in `OperandRef::from_const`
على الرغم من أنه يجب عليك حقًا استخدام نوع غير موقع:
#![feature(const_generics)]
fn factorial<const X: u32>() -> u32 {
match X {
0 => 1,
1 => 1,
_ => factorial::<{ X - 1 }>() + X,
}
}
fn main() {
println!("{:?}", factorial::<10>());
}
هل هناك أي مكان أكثر تنظيماً من هذه المشكلة حيث يمكنني العثور على كيفية استخدامه وأشياء أخرى؟
عادة ما يغطيها الكتاب غير المستقر ، لكن لا يوجد شيء مفيد هناك الآن. عندما تكتشف البتات ، ربما يمكنك التفكير في البدء في رسم بعض المحتوى لذلك؟
عاملي في وقت الترجمة مع ترميز Peano ،
للحصول على مثال على ذلك ، انظر صندوق النوع
نظريًا ، ستعمل التعليمات البرمجية الخاصة بك كما هي تقريبًا
عند استدعاء factorial::<0>
، سيتم ترميز _ => factorial::<{X - 1}>() * X
أليس كذلك؟ لكن محاولة القيام بذلك قد يتسبب في تدفق عدد صحيح.
هل يمكنني أن أتوقع أن يتم تجميع رمز مثل هذا في المستقبل؟
#![feature(const_generics)]
trait NeedsDrop<const B: bool> { }
impl<T> NeedsDrop<std::mem::needs_drop<T>()> for T { }
fn foo<D: NeedsDrop<false>>(d: D) { }
يتعارض هذا مع تطبيق حديث لبعض المصفوفات [T; N]
لـ N <= 32
كإصدارات ثابتة ، لكن الكود التالي لا يتم تجميعه على أحدث ( 4bb6b4a5e 2019-07-11
) كل ليلة مع أخطاء مختلفة the trait `std::array::LengthAtMost32` is not implemented for `[u64; _]`
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct BigintRepresentation<
const N: usize
>(pub [u64; N])
where [u64; N]: std::array::LengthAtMost32,
[u64; N*2]: std::array::LengthAtMost32;
على الرغم من أن ما يلي:
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct BigintRepresentation<
const N: usize
>(pub [u64; N])
where [u64; N]: std::array::LengthAtMost32;
يبدو أن N*2
ليس قيمة ثابتة أو مؤهلًا صالحًا لمثل هذا القيد
shamatar N*2
يجب أن تكون محاطة بأقواس معقوفة مثل `[u64؛ {N * 2}]
أعتقد أن أخطاء "السمة غير مطبقة" تأتي من اشتقاق وحدات الماكرو التي لا تضيف الحد لـ [u64; {N*2}]
، ولكن إذا تمت إزالة المشتقات ، فهناك ICE حاليًا:
"" خطأ: خطأ داخلي في المترجم: ثابت في النوع به خطأ تم تجاهله: TooGeneric
-> src / main.rs: 5: 1
|
5 | / pub هيكلة BigintRepresentation <
6 | | const N: استخدام
7 | | > (pub [u64؛ N])
8 | | حيث [u64؛ N]: الأمراض المنقولة جنسياً :: مجموعة :: LengthAtMost32 ،
9 | | [u64 ؛ {N * 2}]: std :: array :: LengthAtMost32؛
| | ____________________________________________ ^
سلسلة الرسائل "rustc" أصيبت بالذعر عند "عدم وجود أخطاء على الرغم من إصدار delay_span_bug
" ، src / librustc_errors / lib.rs: 366: 17
ملاحظة: قم بتشغيل باستخدام متغير البيئة RUST_BACKTRACE=1
لعرض تتبع خلفي.
هذا الرمز لا يجمع:
#![feature(const_generics)]
struct Foo<const X: usize>([u8; X]);
impl<const X: usize> Foo<X> {
fn new() -> Self {
Self([0u8; X])
}
}
warning: the feature `const_generics` is incomplete and may cause the compiler to crash
--> src/lib.rs:1:12
|
1 | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
error[E0573]: expected type, found const parameter `X`
--> src/lib.rs:5:26
|
5 | impl<const X: usize> Foo<X> {
| ^
| |
| not a type
| help: try using the variant's enum: `regex_syntax::ast::HexLiteralKind`
error[E0107]: wrong number of const arguments: expected 1, found 0
--> src/lib.rs:5:22
|
5 | impl<const X: usize> Foo<X> {
| ^^^^^^ expected 1 const argument
error[E0107]: wrong number of type arguments: expected 0, found 1
--> src/lib.rs:5:26
|
5 | impl<const X: usize> Foo<X> {
| ^ unexpected type argument
error: aborting due to 3 previous errors
npmccallum ، عليك القيام بـ Foo<{X}>
@ pengowen123 نعم ، إنها تجمع (تعطل المحول البرمجي بـ constant in type had an ignored error: TooGeneric
) بدون derive
، ولكن بعد ذلك قد يكون سؤالًا منفصلاً عما إذا كان هذا "القيد المزدوج" يكون فعالاً N <= 32
و N <= 16
لا يستخدمها المترجم.
من المحتمل ألا تعمل التعبيرات التي تشير إلى المعلمات لفترة أطول ، فالعبارات التي تشير إلى المعلمات [T; N]
و Foo<{N}>
تكون ذات غلاف خاص بحيث لا تحتوي على تعبيرات بذكر N
فيها ، ولكن بدلاً من ذلك الرجوع مباشرة إلى المعلمة N
، متجاوزًا المشكلة الأكبر.
استخدام Self
يتسبب في حدوث عطل.
حتى استبداله بـ Value<{C}>
، فإنه لا يزال يتعطل.
#![feature(const_generics)]
struct Value<const C: usize>;
impl<const C: usize> Value<{C}> {
pub fn new() -> Self {
unimplemented!()
}
}
pub fn main() {
let value = Value::new();
}
مقتطفك لا يتعطل في playpen: https://play.rust-lang.org/؟version=nightly&mode=release&edition=2018&gist=d3fda06d2e8b3eb739afa99d5da84a33
مثل # 61338 ، مصدر المشكلة هو التجميع المتزايد.
تجميع الوقت يحسب وظائف بسيطة
أعتقد أن الميزة الأكثر ملاءمة ستكون const fn .
نظريًا ، ستعمل التعليمات البرمجية الخاصة بك كما هي تقريبًا
#![feature(const_generics)] fn factorial<const X: i32>() -> Option<i32> { match X { i if i < 0 => None, 0 => Some(1), 1 => Some(1), i => Some(factorial::<{X - 1}>().unwrap() + i) } } fn main() { println!("{:?}", factorial::<10>()); }
لكنها لا:
warning: the feature `const_generics` is incomplete and may cause the compiler to crash --> src/main.rs:1:12 | 1 | #![feature(const_generics)] | ^^^^^^^^^^^^^^ error: internal compiler error: src/librustc_codegen_ssa/mir/operand.rs:79: unevaluated constant in `OperandRef::from_const`
على الرغم من أنه يجب عليك حقًا استخدام نوع غير موقع:
#![feature(const_generics)] fn factorial<const X: u32>() -> u32 { match X { 0 => 1, 1 => 1, _ => factorial::<{ X - 1 }>() + X, } } fn main() { println!("{:?}", factorial::<10>()); }
هذه الميزة مفيدة لي أيضًا ، const fn
ليس كافيًا. أريد استخدامه لصفيف ذو أبعاد N بشرط إنهاء الأبعاد = 0.
أنا قادر على إنشاء هيكل:
#![feature(const_generics)]
struct MyArray<T: Default, const len: usize> {
real_array: [T; len]
}
impl<T: Default, const len: usize> MyArray<T, {len}> {
fn new() -> Self {
return MyArray {
real_array: [Default::default(); len]
}
}
}
فشل هذا لأنني لا أستطيع بالفعل تهيئة المصفوفة للأسباب التالية:
error: array lengths can't depend on generic parameters
--> src/main.rs:9:46
|
9 | real_array: [Default::default(); len]
|
لقد حاولت العمل على حلها من خلال تعيين قيم ثابتة على القيمة العامة.
هذا يتخطى الخطأ أعلاه ، لكن المترجم يتعطل بعد ذلك.
error: internal compiler error: src/librustc/ty/subst.rs:597: const parameter `height/#0` (Const { ty: usize, val: Param(height/#0) }/0) out of range when substituting substs=[]
تحتاج اللغة بشدة إلى أدوات عامة ثابتة أساسية ، بحيث لا تضطر المكتبة القياسية إلى تحديد كل وظيفة لكل حجم مصفوفة. هذا هو السبب الوحيد الذي يجعلني لا أستخدم الصدأ. هل نحتاج حقًا إلى وظائف وقت تجميع كاملة؟
قد أكون مخطئًا ولكن يجب أن تكون التعبيرات الصحيحة البسيطة كافية وآمل ألا يضيع أحد وقته ، للتأكد من أن هذه الأمثلة الغامضة تعمل.
تحتاج اللغة بشدة إلى أدوات عامة ثابتة أساسية ، بحيث لا تضطر المكتبة القياسية إلى تحديد كل وظيفة لكل حجم مصفوفة
هناك بالفعل بعض الجهد هناك https://github.com/rust-lang/rust/issues/61415.
آمل ألا يضيع أحد وقته في التأكد من أن هذه الأمثلة السخيفة تعمل.
بعض الناس يفعلون ذلك ، لا أرى أي مشكلة في ذلك ؛)
هذا هو السبب الوحيد الذي يجعلني لا أستخدم الصدأ.
هذا هو السبب الأقل إثارة للاهتمام الذي رأيته مقتبسًا عن شخص لا يستخدم الصدأ. هل أنت متأكد من أنك تقول الحقيقة؟
لكن يجب أن تكون التعبيرات الصحيحة البسيطة كافية
حتى جعل هذا النطاق المنخفض أمر صعب للغاية. جرب يدك في ذلك ، لدينا أشخاص قادرون حقًا على القيام بذلك وهناك سبب يجعله يستغرق كل هذا الوقت الطويل.
لسوء الحظ ، لم أتمكن من تخصيص الكثير من الوقت لإصلاح أخطاء الأبراج العامة مؤخرًا (أو الصدأ بشكل عام). إذا أراد أي شخص المشاركة في دفع الأدوية العامة الثابتة ، فسيسعدني تقديم المشورة لمعالجة المشكلات المفتوحة ومراجعة إصلاحات الأخطاء ، على الرغم من أنه من المحتمل أن يستغرق الأمر بعض الوقت قبل أن أتمكن من التركيز على هذا مرة أخرى.
آمل ألا يضيع أحد وقته في التأكد من أن هذه الأمثلة السخيفة تعمل.
لا أحد ، miri
أقوى بكثير من C ++ constexpr
.
ولا أحد يعمل على أي شيء خيالي مثل اشتقاق N = M
من N + 1 = M + 1
.
معظم هذه الأخطاء لا تتعلق بالتعبيرات الموجودة فيها ، إنها تتعلق بنظام الكتابة وكيفية تفاعل const
generics مع جميع الميزات الأخرى.
كانوا لا يزالون هناك إذا كان كل ما لديك هو const
أدوية عامة وأرقام حرفية صحيحة.
بالمناسبة ، أعتقد أن الخطأ "لا يمكن أن تعتمد أطوال المصفوفة على معلمات عامة" لتعبيرات [expr; N]
ليست هناك حاجة ، يمكننا استخدام نفس الحيلة التي نستخدمها لأنواع [T; N]
، وسحب خارج N
بدون تقييمه كتعبير.
بينما أرغب في أخذ طعنة في هذا ، لست متأكدًا من أنني الشخص المناسب. لقد استخدمت القليل من الصدأ وأعرف القليل جدًا من نظرية المترجم. قد أحتاج إلى قدر لا بأس به من التدريب لكنني على استعداد بالتأكيد. 😄
تحرير: لدي قدر لا بأس به من الخبرة في مجال البرمجيات بشكل عام.
varkor ، لقد كنت أبحث عن شيء مفيد rustc
، وأود أن أقدم المساعدة. أيضًا ، شكرًا لصراحتك بشأن قدرتك على تخصيص الوقت لذلك!
varkor ، أنا في الواقع أتابع التعليق أعلاه ، لذا إذا كان لديك أي نصيحة ، فأنا آذان صاغية! لا تتردد في إحالتي إلى قناة اتصال أخرى أيضًا.
شيء واحد يمكننا القيام به الآن ، لقد أدركت للتو السماح بتعبيرات Foo::<{...}>
/ [expr; ...]
للإشارة إلى المعلمات العامة (في الجزء ...
).
هذا لأن التعبيرات يجب أن تتداخل في مكان ما داخل الجسم ، وهذا يميل إلى منع التبعيات الدورية.
ومع ذلك ، أشعر بالقلق من أن وجود مثل [(); [0; 1][0]]
في التوقيع قد ينكسر ، لذلك ربما نحتاج إلى تشغيل فوهة البركان على أي حال (وفي الوقت الحاضر يستغرق ذلك إلى الأبد).
بالنسبة إلى أي شخص مهتم بالمساعدة في استخدام الأدوية العامة ، ستكون نصيحتي هي إلقاء نظرة على قائمة مشكلات الأدوية العامة المفتوحة والتحقيق في أيهما يبدو ممتعًا بالنسبة لك. أجرى البعض بعض التحقيقات بالفعل ، والتي يجب أن تكون في التعليقات. من المحتمل أن تتطلب معظم المشكلات القليل من البحث. من المفيد كتابة تعليق إذا كنت تخطط للتحقيق في شيء ما ، لذلك لا نكرر الجهود (ولكن يمكنك غالبًا تجاهل المسؤول عن المشكلة إذا لم يكن هناك أي نشاط لفترة من الوقت). إذا كان لديك أي أسئلة ، يمكنك طرحها في تعليقات القضية ، أو على Discord أو Zulip. eddyb و yodaldevoid و @ oli-obk وأنا على دراية بالعديد من المجالات ذات الصلة وأشخاص طيبون يجب أن أسألهم. شكرا على جميع اهتماماتكم!
cchameerabbasi ، ranweiler
أسئلة حول كونست جنرالس:
const
من النوع التعسفي؟const
generics التي لم يتم تنفيذها / تعطل المترجم؟ملاحظة (المساهمون:) شكرًا جزيلاً على العمل على هذه الميزة.
لا تزال ملفات const-Genics قيد التطوير ، لذا لا توجد أي مستندات رسمية عليها حتى الآن. لست متأكدًا جدًا من السؤالين الآخرين. عند آخر مرة استخدمت فيها عناصر const-Generic ، تعطلت عندما حددت بعض المعلمات العامة لـ const ، ولكن مر ما يقرب من شهر منذ أن فعلت أي شيء معها ، لذا ربما تغيرت الأشياء منذ ذلك الحين.
ولا أحد يعمل على أي شيء خيالي مثل اشتقاق
N = M
منN + 1 = M + 1
.
سيكون هذا مفيدًا جدًا للحصول على حل لقيود النوع هذه. على سبيل المثال ، عند تنفيذ إضافة إذا كان عدد بتات N ، يجب أن يكون حجم الإرجاع (N + 1) لحساب بت الفائض. عندما (على سبيل المثال) يتم إعطاء رقمين من 5 بتات ، يجب على المحلل التحقق من أن N + 1 = 6
. نأمل أن يتم تثبيت هذا في قائمة الأدوية العامة لاحقًا :)
@ flip111 نعم ، أعتقد أن الخطة هي إضافة هذا لاحقًا ، لكن هذا النوع من قيود التعبير العام معقد للغاية ويصعب تنفيذه. لذلك قد لا نراهم لبضع سنوات على الأقل.
لكي نكون صادقين ، فإن حل هذه الأنواع من المشكلات القائمة على القيود يشبه إلى حد كبير وظيفة Prolog. ربما يكون التحميل على محرك الطباشير خيارًا؟ Afaik يحل السمات ، رغم ذلك ، أليس كذلك؟
بالمناسبة أنا أحب الموضوع ، على الرغم من أنني لا أستطيع المساعدة في هذا الصراف الآلي. شكرًا لكل من يعمل في Const Generics على وقتك والتزامك. 💐
تحديث صغير: أنا أشق طريقي فوق شجرة الصدأ. أخطط للمساهمة ولكني أرغب في الدراسة الذاتية لمكان لا أحتاج فيه إلى تدريب مفرط.
أنا قادر على إنشاء هيكل:
#![feature(const_generics)] struct MyArray<T: Default, const len: usize> { real_array: [T; len] } impl<T: Default, const len: usize> MyArray<T, {len}> { fn new() -> Self { return MyArray { real_array: [Default::default(); len] } } }
فشل هذا لأنني لا أستطيع بالفعل تهيئة المصفوفة للأسباب التالية:
error: array lengths can't depend on generic parameters --> src/main.rs:9:46 | 9 | real_array: [Default::default(); len] |
واجهت نفس المشكلة ، ولكن وجدت حلاً باستخدام
MaybeUninit
:
https://play.rust-lang.org/؟version=nightly&mode=release&edition=2018&gist=3100d5f7a4efd844954a6fa5e8b8c526
من الواضح أنه مجرد حل بديل للحصول على مصفوفات مهيأة بشكل صحيح ، لكن بالنسبة لي هذا يكفي حتى يتم توفير طريقة مناسبة.
ملاحظة: أعتقد أن الكود يجب أن يعمل دائمًا على النحو المنشود ، ولكن إذا وجد شخص ما خطأ في استخدام المادة غير الآمنة ، فسأكون سعيدًا بإصلاحه.
raidwas أنت تقوم بإسقاط ذاكرة غير مهيأة عند استخدام عامل التشغيل =
لتهيئة ذاكرة غير مهيأة. افعل هذا بدلاً من ذلك ،
KrishnaSannasi شكرًا ، التقاط جيد: D (من الناحية الفنية لم أسقط ذاكرة غير مهيأة لأنني
من الناحية الفنية ، فإن إسقاط حتى العوامات غير محدد ، لكنه ليس قابلاً للاستغلال في الوقت الحالي.
من الناحية الفنية ، فإن إسقاط حتى العوامات غير محدد ، لكنه ليس قابلاً للاستغلال في الوقت الحالي.
كنت أتوقع أن إسقاط أي نوع Copy
، حتى الأنواع غير المهيأة ، يعد أمرًا محظورًا. ربما هذا يستحق التغيير.
من الناحية الفنية ، فإن إسقاط حتى العوامات غير محدد ، لكنه ليس قابلاً للاستغلال في الوقت الحالي.
كنت أتوقع أن إسقاط أي نوع
Copy
، حتى الأنواع غير المهيأة ، يعد أمرًا محظورًا. ربما هذا يستحق التغيير.
لا يزال من الناحية الفنية UB. بينما يُعد إسقاط قيم Copy
المحددة بأمان أمرًا غير عملي ، فقد يقرر المترجم إجراء بعض التحسينات غير المتوقعة إذا حاولت إسقاط ذاكرة غير مهيأة من أي نوع (على سبيل المثال ، إزالة جميع التعليمات البرمجية التي من المحتمل أن تلامس هذه القيمة) ، والتي ربما يكسر الأشياء. هذا هو فهمي لها.
لكي لا تكون غير مهذب ، ولكن ≥ يتم إخطار 60 شخصًا بشأن التعليقات على سلسلة الرسائل هذه ، لذلك يجب علينا على الأرجح إبقاء المناقشة خارج الموضوع عند الحد الأدنى. دعنا بدلاً من ذلك نستخدم هذا لتنسيق العمل على الأدوية العامة لأن هذا ما نريد جميعًا حدوثه.
تعطل إذا استخدمت _aliases تشير إلى الكتابة باستخدام const-param_ من صندوق آخر (تبعية).
على سبيل المثال:
نوع حانة الاسم المستعار
هيكل حانة
- crate B
قفص خارجي - a ؛
استخدام crate_a :: الاسم المستعار ؛
pub fn inner_fn (v: Alias
""
سجل الأعطال (44580) .txt
@ fzzr- يبدو مثل # 64730
يبدو أيضًا مثل https://github.com/rust-lang/rust/issues/61624
لقد قمت بتبديل بعض الأكواد إلى أدوات إنشاء ثابتة ويبدو أن هناك حالتين مختلفتين من حالات الاستخدام. لست متأكدًا مما إذا كان ينبغي الخلط بينها أو ما إذا كان من الأفضل لنا استخدام صيغتين مختلفتين لحالات الاستخدام.
الكثير من استخداماتي ليست في الواقع للأنواع التي تلعب فيها القيمة الثابتة دورًا في تحديد الأنواع ، ولكن بدلاً من ذلك للاستفادة من الميزات التي تم قفلها للقيم غير الثابتة / الحرفية (لا تزال غير مدعومة بالكامل ، على سبيل المثال أنماط المطابقة ، ولكن في النهاية يجب أن يكون).
IMHO يجب أن نحدد رسميًا "وسيطات ثابتة" جنبًا إلى جنب مع العوامل الثابتة ، بحيث لا يكتب الناس رمز متحور يقدم ألف "عامل ثابت" (واحد لكل وسيطة) لجعل المترجم يقيم متغيرات معينة على أنها حرفية / ثوابت.
mqudsi هل يمكنك إعطاء مثال؟ هناك بالفعل خطط وعمل تأسيسي مستمر لجعل التقييم الثابت أكثر قوة. هذا متعامد مع الأدوية الجنيسة ، رغم ذلك.
ما أعنيه هو ، إذا كنت تريد إعادة بناء كود محلل نموذجي مثل ما يلي لإعادة استخدامه:
let mut result: u32 = 0;
let mut digits = 0;
while digits < max_digits && src.has_remaining() {
match src.get_u8() {
d<strong i="6">@b</strong>'0'..=b'9' => {
result = result*10 + (d - b'0') as u32;
digits += 1;
},
b'>' => match result {
0..=191 => break, // valid range
_ => return Err(DecoderError::OutOfRange),
},
_ => return Err(DecoderError::Malformed)
}
}
يمكنك عادةً نقلها إلى دالة ، باستثناء ما يلي لن يعمل لأن بعض القيم المستخدمة في مطابقة النمط أصبحت متغيرات:
#[inline(always)]
fn read_str_digits<B: bytes::buf::Buf>(src: &mut B, stop_word: u8,
max_digits: u8, min_value: u32, max_value: u32) -> Result<u32, DecoderError> {
let mut result: u32 = 0;
let mut digits = 0;
while digits < max_digits && src.has_remaining() {
match src.get_u8() {
d<strong i="10">@b</strong>'0'..=b'9' => {
result = result*10 + (d - b'0') as u32;
digits += 1;
},
stop_word => match result {
min_value..=max_value => break, // valid range
_ => return Err(DecoderError::OutOfRange),
},
_ => return Err(DecoderError::Malformed)
}
}
...
}
إذا حطت العقاقير البديلة للإنشاءات قبل الحجج الثابتة ، فيمكنني فجأة إساءة استخدام الأدوية العامة للإنشاءات للتوصل إلى ما يلي:
#[inline(always)]
fn read_str_digits<const MinValue: u32, const MaxValue: u32, const StopWord: u8, B: bytes::buf::Buf>
(src: &mut B, max_digits: u8) -> Result<u32, DecoderError> {
let mut result: u32 = 0;
let mut digits = 0;
while digits < max_digits && src.has_remaining() {
match src.get_u8() {
d<strong i="14">@b</strong>'0'..=b'9' => {
result = result*10 + (d - b'0') as u32;
digits += 1;
},
StopWord => match result {
MinValue..=MaxValue => break, // valid range
_ => return Err(DecoderError::OutOfRange),
},
_ => return Err(DecoderError::Malformed)
}
}
...
}
اعتبارًا من اليوم ، حتى هذا الرمز لن يعمل لأن المترجم لا يكتشف القيم العامة الثابتة لتكون ثوابت صالحة للاستخدام في نمط ، ولكن من الواضح أن هذا غير صحيح ويجب معالجته قبل أن يتمكن RFC 2000 من الهبوط. لا تفهموني خطأ ، لقد كنت أقاتل من أجل الثوابت العامة لسنوات ولدي علاقات عامة جاهزة للذهاب لعشرات الصناديق الرئيسية (لا أطيق الانتظار لجعل المنطقة الزمنية في chrono
a const عامة و توحيد جميع أنواع DateTime
المختلفة) ، لكن imho إذا أصبح من الممكن إساءة استخدام أدوات إنشاء المعاملات لتزوير وسيطات ثابتة (حيث نعني بكلمة "const" ما نعنيه حقًا "حرفيًا") ، فحينئذٍ ستشهد انتشارًا واسعًا إساءة استخدام ذلك.
انها ليست بالضرورة نهاية العالم، ولكن دون وجود حفر عميقا جدا في ذلك، فإنه يبدو كما لو أن التنفيذ الأدوية CONST السليم والكامل سوف تشمل بالضرورة جميع السباكة الحجج CONST على أي حال، ولذا فإننا قد كذلك تأخذ من الوقت الاضافي لوضع اللمسات الأخيرة على بناء الجملة / ux / قصة لحجج كونستانت أثناء وجودنا فيه وتجنب عصر مؤسف من الرائحة الكريهة. نعم ، لا يزال من الممكن عمل ما سبق باستخدام وحدات الماكرو ، لكن بيئة العمل الخاصة بالأدوية الوراثية أسهل ألف مرة.
fwiw ، هذه هي الطريقة التي أتخيل بها نسخة وسيطة const لتبدو كما يلي:
#[inline(always)]
fn read_str_digits<B: Bytes>(src: &mut B, min_value: const u32,
max_value: const u32, stop_word: const u8, max_digits: u8) -> Result<u32, ()> {
let mut result: u32 = 0;
let mut digits = 0;
while digits < max_digits && src.has_remaining() {
match src.get_u8() {
d<strong i="23">@b</strong>'0'..=b'9' => {
result = result*10 + (d - b'0') as u32;
digits += 1;
},
stop_word => match result {
min_value..=max_value => break, // valid range
_ => return Err(()),
},
_ => return Err(())
}
}
...
}
سيكون عمليا متطابقة مع علم الثوابت ولكن بالنسبة إلى دلالات الألفاظ.
يمكنك عادةً نقلها إلى دالة ، باستثناء ما يلي لن يعمل لأن بعض القيم المستخدمة في مطابقة النمط أصبحت متغيرات:
يبدو هذا وكأنه حالة استخدام تتم معالجتها بسهولة أكبر من خلال السماح باستخدام قيم المتغيرات المرتبطة في أنماط (وليس فقط ثوابت) ، مع بعض الصيغ الجديدة. حقيقة أن الثوابت مسموح بها حاليًا في الأنماط هي أمر غير بديهي وتاريخي على حد علمي.
mqudsi سامحني إذا كان هذا سؤالًا سخيفًا ، لكنني لا أرى أي خطأ في المثال الذي قدمته. يبدو لي أنه حالة استخدام صالحة تمامًا للأدوية الثابتة: وجود تعريف معمم للعمل مع القيم العشوائية مثل max / min. لا أرى حقًا فوائد الحجج الثابتة على الأدوية العامة. يبدو أنها تعادل لي. وهذا يعني أن الحجج الثابتة يمكن تنفيذها فقط على أنها إلغاء للأدوية الثابتة. هل يمكنك توضيح المزيد حول الخطأ في نمط التصميم هذا؟
فيما يلي ملخص للعمل المتعلق بالعوامل الثابتة منذ التحديث الأخير . في المرة الأخيرة ، كان الأمر كله يتعلق بالتنفيذ الأساسي: التأكد من أن كل شيء ملائم معًا واجتياز بعض حالات الاختبار الأساسية. منذ ذلك الحين ، تركز الجهد على جعل الأدوية العامة الثابتة أكثر موثوقية: إصلاح الحالات التي عطلت المترجم ، أو لم تعمل بشكل غير متوقع ، أو تحسين التشخيص. نحن نقترب من شيء يعمل بشكل موثوق به ، على الرغم من أنه لا يزال هناك طريق لنقطعه.
بالإضافة إلى ذلك ، انتهى العمل الآخر في المترجم بإصلاح بعض المشكلات الأخرى المتعلقة بالأدوية الثابتة.
لقد بدأنا أيضًا في استخدام عوامل const Genics داخل المترجم نفسه: تستخدم تطبيقات سمة المصفوفة الآن عوامل const Genics بفضل عمل @ crlf0710 و scottmcm (https://github.com/rust-lang/rust/pull/60466، https : //github.com/rust-lang/rust/pull/62435) ، مما أدى إلى تحسينات في الأداء ، والذي سيسمح لنا أيضًا بإلغاء تقييد عمليات تنفيذ سمات الصفيف في المستقبل (عند استقرار العوامل الثابتة). استخدم Centril نفس الأسلوب لتحسين VecDeque
(https://github.com/rust-lang/rust/pull/63061).
تم إصلاح العديد من الأخطاء الشائعة بشكل خاص مع الأدوية العامة الثابتة في الأشهر القليلة الماضية. يبحثnikomatsakis عن التطبيع البطيء ، والذي يجب أن يصلح مجموعة من المشكلات المتبقية ، بينما يبحث jplatte في إصلاح توضيح معلمات const من معلمات النوع (لذلك لن تضطر بعد الآن إلى كتابة {X}
مقابل حجة const).
أود أيضًا أن أشكر eddyb على كل ما قدموه من توجيه ومراجعة
لا يزال هناك عدد كبير من المشكلات الأخرى التي يجب معالجتها ، وكما في السابق ، يمكننا استخدام كل المساعدة التي يمكننا الحصول عليها - إذا كنت مهتمًا بمعالجة أي من المشكلات المتبقية ، فلا تتردد في الاتصال بي بشأن المشكلة أو Discord أو Zulip للحصول على مؤشرات حول البدء.
mqudsi @ mark-im هل سيكون من المناسب تمديد البديل النحوي الحالي للأدوية العامة ، impl Trait
في موضع الوسيطة ، إلى الأدوية العامة؟ هذا هو بناء الجملة mqudsi المقترح لحالة الاستخدام هذه.
أنا شخصياً أعتقد أن هذا سيحسن قابلية قراءة مثل هذه الحالات ، لكني أرى مشكلة واحدة: يتم استخدام الأدوية الجنيسة العادية لتمرير البيانات ، لذا فهي مرتبطة بالحجة. ليس هذا هو الحال بالنسبة للأدوية الثابتة ، فكيف يمكنك تجاوزها؟ ادعي أنها الحجج؟
في حالة impl Trait
في موضع الوسيطة ، لا يمكن أيضًا استخدامه مع بناء الجملة التوربيني. بالنسبة إلى الوسيطة const
، سيكون معكوسًا. قد يكون هذا محيرا.
لست متأكدًا مما إذا كانت الفوائد تفوق "الغرابة" هنا ، لكنني أردت مشاركة أفكاري على أي حال.
تذكرت بشكل غامض مناقشة حول هذا من قبل ، والآن وجدته: https://internals.rust-lang.org/t/pre-rfc-const-function-arguments/6709
@ PvdBerg1998 التي تبدو فكرة سيئة للغاية. لا أفهم حقًا فكرة أن <…>
عبارة عن بناء جملة صعب القراءة. هناك احتمالان:
where
؟قارن الآن مع ما قبل RFC المرتبط أعلاه. سيكون إدخال _tag_ (بمعنى نظام النوع) مباشرة في موضع وسيطات الوظيفة ، أي الارتباطات المتغيرة لجسم الوظيفة.
بعبارة أخرى: إنه أمر محير للغاية ، وكما ذكر العديد من الأشخاص لضمين السمة في موقف النقاش ، فهي ليست ضرورية. من فضلك لا ترتكب نفس الخطأ مرتين لإضافة ميزة لا تستحق ذلك. خاصة إذا كنت "تتظاهر بأنها مجادلات". سيكون الصدأ يسير في الاتجاه الخاطئ هنا. يجب أن يكون بناء الجملة أبسط ، نعم ، لكن ليس أكثر إرباكًا. توقف أرجوك.
تضمين التغريدة
أنا شخصياً أتفق تمامًا مع الاقتراح المرتبط بأن السماح للثوابت في موضع المناقشة سيكون حقًا دفعة جيدة من الناحية البشرية. لا يتعلق الأمر فقط بتوقيعات الوظائف (يمكن القول إن الجمل where
لا "تحل" المشكلة على الإطلاق ، ولكنها ستجعل من الصعب فهم التوقيعات ، حيث يتعين عليك تحليل 3 أماكن بدلاً من واحدة فقط) ، ولكن أيضًا حول كيف سيتم استخدام هذه الوظائف. قارن:
let r = _mm_blend_ps::<{2 * C}>(a, b);
let r = _mm_blend_ps(a, b, 2 * C);
السطر الثاني طبيعي في رأيي أكثر من السطر الثاني. مثال آخر هو إنشاء المصفوفة: MatrixF32::new(3, 3)
مقابل MatrixF32::new::<3, 3>()
. لا أوافق بشدة على أن هذه الوظيفة ستكون "مربكة للغاية". بالنسبة للمستخدم ، لا يعدو كونه متطلبًا إضافيًا لوسيطة دالة. يمكننا بالفعل محاكاة وسيطات const عبر وحدات الماكرو (انظر مضمون SIMD داخل std
) ، لكنها قبيحة وغير فعالة.
فيما يتعلق بـ impl Trait
في موضع النقاش ، كنت في البداية أيضًا ضد هذه الميزة ، لكن بعد مرور بعض الوقت غيرت رأيي وأعتقد أنه كان قرارًا جيدًا في النهاية. الجزء الوحيد غير المكتمل في الوقت الحالي هو التفاعل مع معلمات النوع الصريحة التي توفرها عبر التوربيني. أعتقد أن الحل الجيد هو جعل الحجج impl Trait
غير مرئية بالنسبة إلى التوربيني ، أي يجب على المستخدمين استخدامها عندما يتأكدون من عدم الحاجة إلى توضيح نوع واضح. سيسمح لنا بتقليل الحاجة إلى _
داخل التربو في بعض السيناريوهات بشكل كبير.
أعتقد أن مناقشة الحجج الثابتة هي خارج الموضوع هنا ، لذا ربما لا ينبغي أن تستمر هنا.
أحد الأشياء التي تفصل بين الوسيطات const
الوسيطات impl Trait
(التي ذكرها @ PvdBerg1998 ) هو أنها عبارة عن وسيطات ، مع كل ما يعنيه ذلك بالنسبة للاستدلال بالنوع.
لا يمكنك تمرير نوع نفسها حجة، ولكن يمكنك تمرير قيمة، وترك وظيفة يستنتج حججها العامة CONST من الحجج قوسين طبيعية لها من المعقول تماما.
هذا شائع إلى حد ما في C ++ ، على سبيل المثال:
template <typename T, size_t N>
size_t length(T (&array)[N]) {
return N;
}
وهذا يختلف بمهارة من مجرد قبول المعلمة CONST وdesugaring إلى معلمة العامة CONST ( fn foo(const N: usize)
-> fn foo<const N: usize>()
). إنه أقرب إلى تقييد معلمة بمعامل ثابت عام ، ثم استنتاج هذه الوسيطة العامة الثابتة من الوسيطة. لذلك قد يبدو مثال المصفوفة أعلاه كما يلي:
impl<const W: usize, const H: usize> MatrixF32<W, H> {
fn new(w: usize<W>, h: usize<H>) -> Self { .. }
}
... حيث usize<X>
عبارة عن بناء جملة مكون من أجل "a usize
بقيمة X
." (وبالمثل ، قد ترغب في الحصول على usize<X..Y>
للأنواع المتباينة ، والتي تمت مناقشتها في سياق تعميم NonZero
.)
إذا كنت ترغب في تجنب التشبث في الأنواع ذات النطاق المتنوع ، فقد تنظر إلى اللغات المكتوبة التابعة والتي تسمح باستخدام المعلمات مباشرة في الأنواع ، مع القليل من التغيير والتبديل في النطاق:
fn new(const W: usize, const H: usize) -> MatrixF32<W, H> { .. }
إنها ليست حجج. هم من الأدوية الجنيسة . على مستوى نظام النوع ، هذا يعني أن _values_ يعيش في وقت الترجمة ، بينما تعيش قيم وسيطة الدالة في وقت التشغيل. خلط كلاهما مضلل للغاية.
نظرًا لأنني مهتم بأنظمة الكتابة ، فإن هذا الاقتراح يتعارض مع الكثير من المبادئ السليمة والعقلانية. لا تريد خلط القيم والأنواع. لأنه ، نعم ، N
(ملاحظة لم أقل usize
، قلت N
) ، على الرغم من أنك تعتقد أنها قيمة ، فهي أقرب إلى النوع من قيمة. كمبرر منطقي ، لا تمتلك Haskell أنواعًا ثابتة ولكن لديها DataKinds
، مما يسمح برفع منشئي البيانات العاديين كأنواع:
foo :: Integer -> Integer
foo 0 -- 0 has type Integer
-- but
data P (a :: Integer)
type MyP = P 10 -- 10 has kind Integer, which “value” is the 10 type
وبالتالي:
fn foo<const X: usize>()
هنا ، X
أقرب إلى النوع من القيمة.
أيضا ، أنا أهتم بأحادية الشكل. إذا قرأت هذا:
let x = foo(12, "Hello, world!", None);
مع اقتراحك ، إذا نظرنا إلى تعريف foo
، فمن الصعب معرفة الحجج التي ستعمل على تحويل foo
. لأنك في كل مرة تقوم فيها بتمرير قيمة مختلفة لعامل ثابت ، تقوم بإنشاء وظيفة جديدة كاملة.
ربما يبدو الأمر أكثر سهولة بالنسبة لك ولأسبابك ، ولكن لدي أيضًا أسبابًا لأقول إنه غير بديهي على الإطلاق من حيث صحة النوع. إن الإشارة إلى أنها وسيطات تشبه الإشارة إلى أن الدوال ذات المعلمات ، في الرياضيات ، لها وسيطات المعلمات الخاصة بها. أنت تخلط بين المعلمات والحجج ، وتبين مدى سوء هذه الفكرة.
ربما أخطأت في قراءتي ، لقد قلت على وجه التحديد " const
وسيطات ... هي وسيطات " ، وليس " const
generics." يعد مثال Rust الأول الخاص بي مكافئًا تمامًا لـ DataKinds ( usize<N>
هو الإصدار على مستوى النوع من N
). لا توجد مشكلة هنا فيما يتعلق بصحة النوع - فأنا لا أجادل من حيث الحدس ولكن عن طريق القياس على الأنظمة القائمة والراسخة وأنظمة الصوت.
أما بالنسبة لقلقك بشأن monomorphization - فهذا لا يختلف عما هو عليه اليوم! يمكن أن تتسبب كل حجة في تكوين أحادي الشكل جديد. أود أيضًا أن أضيف أن الحل لهذه المشكلة هو تقليل تكلفة جميع الأدوية الجنيسة من خلال مشاركة التعليمات البرمجية غير المعتمدة بين الحالات ، بما في ذلك - وعلى وجه الخصوص عن طريق تحويل العوامل الثابتة إلى قيم وقت التشغيل عندما يكون ذلك ممكنًا.
(وأنا في حيرة شديدة من ادعائك بأنني أخلط بين المعايير والحجج ، وكنت حريصًا على التمييز بينها).
أفهم ما تقصده ولكني ما زلت أشعر بقلق شديد. نظرًا لأن _argument_ تم تمييزه بعلامة _const_ ، فهذا يعني أنه لا يمكنك تمريرها _a value_ ، أثناء التحدث. أنت بحاجة لتمريرها _قيمة ثابتة_ ، والتي سيتم تعيينها إلى _const عام_. بالمناسبة ، لم تذكرها هنا ولكن هذا مجرد تطبيق من نوع سينغليتون_ إذا كنت تفكر في 10
كنوع: قيمته الوحيدة الممكنة هي 10
.
نظرًا لأنني كنت ضد السمة الضمنية في موقف النقاش ، فأنا ضد ذلك أيضًا (وستعرف سبب قدرتنا على المقارنة هنا). عدة نقاط:
<…>
أصعب من (…)
، لا سيما بالنظر إلى struct
مقابل fn
. حاليًا ، يوجد لدى struct
فقط <…>
و fn
كلاهما ، لأنه يمكن تعيين المعلمات على كلاهما.foo<A, B>
، فأنت تعلم أن هناك معلمتين ستؤديان إلى تعريف الوظيفة وتنفيذها.أشعر بما تريد أن تفعله هنا. foo(1, 3)
أفضل من foo<3>(1)
، لكن ليس بالنسبة لي. والسبب في ذلك هو أن foo(1, 3)
يجب أن يقبل الوسيطة الثانية لتكون قائمة على وقت التشغيل وأن الاقتراح الذي تقدمه يمنعه. يمكنني رؤية التطبيقات ، مع ذلك ، خاصةً مع المصفوفات ، لكني حاليًا لا أحب الشكل الذي تبدو عليه. سأكون أكثر من ذلك بكثير لحل يقول "إذا كانت الوسيطة هي const
، فيمكننا استنتاج نوع متغير / عام ثابت.
fn foo<const N: usize>(a: usize, b: usize | N);
هذا مجرد بناء جملة تخيلي توصلت إليه لشرح وجهة نظري: إذا مررت b
كقيمة ثابتة ، N = b
وينتهي بك الأمر بصيغة لطيفة:
foo(1, 3)
إذا لم يكن b
قيمة ثابتة ، فيجب عليك تمرير N
صراحة:
foo<3>(1, x)
أيضًا ، ماذا سيكون بناء الجملة لهذا ، مع اقتراحك:
fn foo<const N: usize>(x: [f32; N]);
fn new(const W: usize, const H: usize) -> MatrixF32<W, H> { .. }
يقودنا إلى التساؤل حول العناصر المرتبطة ، باختصار ،
new()
هي وظيفة مرتبطة ، ويجب أن تكون مرتبطة بنوع ملموس ، العناصر العامة لـ const لها دلالات مثل "هذا النوع له هذه المعلمة ..." ، أي النوع التابع. لذلك ، لا ينبغي أن يحتويnew()
في السياق على أي وسيطات. يجب أن يبدو استخدام التوضيح مثلType<32>::new()
. وبالطبع يجب أن تكون جميع الحجج المتعلقة بالأدوية العامة قابلة للنقاش.
أشعر بما تريد أن تفعله هنا. foo (1، 3) يبدو أفضل بالنسبة لك من foo <3> (1) ، لكن ليس بالنسبة لي. والسبب في ذلك هو أن foo (1 ، 3) يجب أن يقبل الوسيطة الثانية لتكون قائمة على وقت التشغيل وأن الاقتراح الذي تقدمه يمنعه.
هذا ليس دافعي ولا نيتي - أنا لا أتحدث عما "أشعر بتحسن" ولا أعتقد أن التمييز بين التجميع / وقت التشغيل يحتاج إلى الخلط مع التمييز على مستوى النوع / القيمة. الاثنان منفصلان بالفعل - العناصر const
(القيمة أو fn) هي بالتأكيد ليست من الأنواع!
كل ما أحصل عليه هو الاتصال الدلالي الذي يرسمه الاستدلال بين معلمات مستوى القيمة ومعلمات مستوى النوع. لا توجد علاقة بـ impl Trait
- كانت وجهة نظري ، مرة أخرى ، هي التمييز بين الحجج الثابتة من impl Trait
، على وجه التحديد لتفادي هذا النوع من القلق غير المنتج.
أيضًا ، ماذا سيكون بناء الجملة لهذا ، مع اقتراحك:
fn foo<const N: usize>(x: [f32; N]);
لن يتغير هذا التركيب! أنا لا أقترح إزالة معلمات const من مستوى النوع (نحويًا أو معنويًا) ، فقط نقوم بإضافتها إلى مستوى القيمة ، جزئيًا للمساعدة في استنتاج مستوى النوع.
في cppcon ، كان هناك حديث عن معلمات دالة constexpr ، والتي تبدو مشابهة لما يتحدث عنه @ PvdBerg1998 ويبدو تمامًا مثل الخيط الداخلي الذي يرتبط به @ mark-im. يبدو أنه تم استقباله بشكل جيد هناك.
تبدو فكرة جيدة ، ولكن يجب العمل عليها بعد الانتهاء من التنفيذ الأولي للأدوية الثابتة
CppCon 2019: David Stone - إزالة Metaprogramming من C ++ ، الجزء 1 من N: معلمات دالة constexpr
تحرير: تم ذكر هذا في هذا الموضوع ، وهنا الورقة ذات الصلة لمعلمات دالة constexpr
https://github.com/davidstone/isocpp/blob/master/constexpr-parameters.md
أود أن أطلب أن نحتفظ بمناقشة مثل هذا التغيير النحوي الهام إما لخيط في الأجزاء الداخلية أو قضية (أو تعديل العلاقات العامة) في RFCs repo. قسم التعليقات الخاص بهذه المشكلة طويل جدًا بالفعل ويبدو أن بناء الجملة المعني غير ضروري لـ MVP القابل للاستخدام من الأدوية العامة الثابتة.
إذا استطعنا نقل التعليقات فربما سنفعل. قد نرغب في قفل المشكلة على أعضاء فريق @ rust-lang وإخفاء جميع التعليقات الخارجية؟
يجب أن تتم جميع مناقشات التصميم في RFC repo ويجب أن تكون جميع تقارير الأخطاء في مشكلات منفصلة.
cc @ rust-lang / moderation هل هناك سابقة للقيام بذلك؟
يمكنك _ تحويل_ تعليق على مشكلة ، لكن لا يمكنك نقل التعليقات. الإغلاق جيد ، وسأخفي فقط تعليقات الموضوع.
مع بداية العام الجديد ، اعتقدت أنه سيكون من الجيد تقديم تحديث آخر حول ما نحن فيه الآن مع الأدوية الثابتة. لقد مر أكثر من عامين بقليل منذ أن تم قبول RFC للأدوية الثابتة . في السنة الأولى (تقريبًا 2018) ، تم بذل سلسلة من جهود إعادة البناء الكبيرة لتسهيل الأدوية البديلة عن طريق تحسين التعامل مع المعلمات العامة بشكل عام في جميع أنحاء المترجم. في السنة الثانية (تقريبًا 2019) ، بدأ العمل على تطبيق الأدوية العامة الثابتة نفسها: أولاً عن طريق الحصول على الحد الأدنى من العمل ، ثم إبطاء تحسين تكامل الميزة. بدأ الناس أيضًا في تجربة استخدام العوامل الثابتة في المترجم نفسه. توجد أوصاف أكثر تفصيلاً لهذه الجهود في أول نشرتي تحديث: [1] ، [2] .
كان هناك تقدم جيد في الشهرين الماضيين منذ التحديث الأخير.
{}
(https://github.com/rust-lang/rust/pull/66104)structural_match
لمنع الأنواع ذات التحقق من المساواة المخصص من استخدامها كأدوية ثابتة (https://github.com/rust-lang/rust/pull/65627)شكراً جزيلاً لكل من كان يساعد في الأدوية الجنيسة!
ماذا بعد؟ أكبر مانع للأدوية الثابتة في الوقت الحالي هو التطبيع البطيء ، وهو مطلوب لأنواع معينة من الحدود العامة للثوابت (مثل المصفوفات ). يبحث @ skinny121 حاليًا عن التطبيع البطيء ، ويواصلون جهودهم الرائعة في القضاء على الأخطاء الكبيرة في الأدوية الجنسية. هذا من شأنه أن يعالج العديد من القضايا الحالية مع الأدوية الثابتة.
بغض النظر عن التطبيع البطيء ، لا يزال هناك عدد كبير من الأخطاء وورق الورق التي نرغب في معالجتها. إذا كنت مهتمًا بمعالجة أي من المشكلات المتبقية ، فلا تتردد في الاتصال بي بشأن المشكلة ، أو على Discord أو Zulip للحصول على مؤشرات حول البدء. أنا واثق من أنه يمكننا إحراز تقدم جيد في عام 2020 ونأمل أن نقترب من نقطة يصبح فيها الاستقرار مناقشة قابلة للتطبيق!
هل هناك مجموعة فرعية من الأدوية العامة الثابتة التي لا تصل إلى التطبيع البطيء ولا تحتوي على العديد من الأخطاء وورق الورق ، ولكنها يمكن أن تعبر عن قدر كبير من التعليمات البرمجية المفيدة؟ لقد لاحظت أن إشارات الأمراض المنقولة بالاتصال الجنسي للعديد من سمات المصفوفات تبدو أنها تعمل بشكل جيد. ربما يكون هناك تضييق من شأنه أن يسمح للصناديق الأخرى بكتابة نوع الضمانات التي لدينا في الأمراض المنقولة جنسياً لسماتها الخاصة ، على الرغم من أنها لا تدعم جميع وظائف مربو الحيوانات؟
نحن الآن أكثر من نصف الطريق خلال العام ، لذلك سألخص بإيجاز العمل الجاري. كان هناك الكثير من الأشخاص الذين شاركوا في تحسين دعم الأدوية العامة في الأشهر الستة الماضية ، لذا نشكرك على كل من ساعد بطريقة ما! أود بشكل خاص أن أشكر @ skinny121 و lcnr ، اللذين عالج كلاهما بعض الميزات الكبيرة التي تفتقر إليها الأدوية العامة الثابتة لفترة من الوقت: التطبيع البطيء للثوابت ودعم حجة const في استدعاءات الطريقة ، بالإضافة إلى إصلاح العديد من الأخطاء الصعبة. جهودهم واضحة من الملخص أدناه.
يتم الآن استخدام العناصر العامة لـ Const في عدة أماكن في جميع أنحاء المترجم ، وهناك بالفعل تجارب مع السمات والوظائف التي تستخدم عوامل const ، على سبيل المثال slice::array_chunks
و IntoIterator
و FromIterator
مقابل [T; N]
(https://github.com/rust-lang/rust/pull/65819 ، https://github.com/rust-lang/rust/pull/69985). يتم أخيرًا أيضًا إعداد حد الطول 32 لتطبيقات سمات الصفيف للإزالة .
نحن نناقش حاليًا تثبيت مجموعة فرعية من الأدوية العامة الثابتة التي يجب أن تغطي مجموعة واسعة من حالات الاستخدام (على الرغم من أنه لا تزال هناك بعض المشكلات التي يجب معالجتها قبل أن يتم تثبيت الأدوية العامة الثابتة بشكل كامل).
unused_braces
(https://github.com/rust-lang/rust/pull/70081)dyn Trait
للمعلمات العامة لـ const (https://github.com/rust-lang/rust/pull/71038)على الرغم من أن الأدوية الجنيسة قد قطعت شوطًا طويلاً بالفعل ، فلا تزال هناك أخطاء وحواف حادة . إذا كنت مهتمًا بمعالجة أي من المشكلات المتبقية ، فلا تتردد في الاتصال بي أو lcnr أو
التعليق الأكثر فائدة
فيما يلي ملخص للتقدم المحرز حتى الآن في الأدوية العامة.
قبل أن يبدأ العمل على الأدوية العامة الثابتة بشكل صحيح ، كان هناك بعض إعادة الهيكلة التي يجب القيام بها. تولى jplatte المهمة مع https://github.com/rust-lang/rust/pull/45930. بعد ذلك ، بدأ jplatte العمل على التطبيق الرئيسي للأدوية الثابتة ، لكنه اكتشف أنه لم يكن لديه الوقت الكافي للمتابعة.
التقطت أنا و yodaldevoid المكان الذي توقفت فيه https://github.com/rust-lang/rust/pull/48149 ، https://github.com/rust-lang/rust/pull / 48452 ، https://github.com/rust-lang/rust/pull/48523 ، https://github.com/rust-lang/rust/pull/51880.
مع القيام بذلك ، يمكن أن يبدأ تطبيق الأدوية العامة بجدية. منذ ذلك الحين ، عملت أنا و https://github.com/rust-lang/rust/pull/58191 ، https://github.com/rust-lang/rust / pull / 58503 ، https://github.com/rust-lang/rust/pull/58581 ، https://github.com/rust-lang/rust/pull/58583 ، https://github.com/rust -lang / rust / pull / 59170 ، https://github.com/rust-lang/rust/pull/59355 ، https://github.com/rust-lang/rust/pull/59415 ، https: // github .com / rust-lang / rust / pull / 60058 ، https://github.com/rust-lang/rust/pull/60280 ، https://github.com/rust-lang/rust/pull/60284 and most مؤخرًا https://github.com/rust-lang/rust/pull/59008. (تم فصل هذه في الغالب عن
ما هو الوضع الآن؟ تعمل بعض الاختبارات العامة لـ const ومع ذلك ، لا تزال هناك اختبارات لا تعمل ، وهناك عدد من
FIXME
s في جميع أنحاء الكود الذي لا يزال يتعين علينا معالجته. نحن نقترب الآن ، رغم ذلك ، ونحن في مرحلة حيث توجد بعض الفاكهة المتدلية إذا كنت تريد المساعدة.FIXME(const_generics)
منتشر في جميع أنحاء الكود. نحن نخطط للعمل في طريقنا من خلالها ، لكن yodaldevoid ولدي الكثير من الوقت فقط ، لذلك إذا كنت تعتقد أنه يمكنك معالجة واحدة ،لقد قمت بكتابة نظرة عامة على بعض مشكلات التنفيذ المتبقية قبل أن تصبح أدوات const Genics جاهزة للاختبار المناسب ، في المنشور العلوي ، لإعطاء فكرة تقريبية عما تبقى للقيام به.
لقد استغرق الأمر وقتًا ، لكننا نحقق تقدمًا مطردًا ونأمل في مواكبة الوتيرة. إنه لأمر محفز أن ترى أخيرًا الأشياء بدأت في الظهور!