صدأ 1.27 الإصدار

يسر فريق تطوير Rust أن يعلن عن إصدار نسخة جديدة من Rust: 1.27.0. Rust هي لغة برمجة نظام تهدف إلى الأمان والسرعة وتنفيذ التعليمات البرمجية المتوازية.


إذا كان لديك إصدار سابق من Rust مثبتًا باستخدام rustup ، فإن ترقية Rust إلى الإصدار 1.27.0 تحتاج فقط إلى:


$ rustup update stable 

إذا لم تكن قد قمت بالفعل بتثبيت rustup ، فيمكنك تثبيته من الصفحة المقابلة على موقعنا. تتوفر ملاحظات الإصدار التفصيلية لـ Rust 1.27.0 على GitHub.


نود أيضًا أن نلفت انتباهك إلى هذا: قبل إصدار الإصدار 1.27.0 ، اكتشفنا خطأ في تعيينات match المقدمة في الإصدار 1.26.0 ، مما قد يؤدي إلى سلوك غير صحيح. نظرًا لأنه تم اكتشافه في وقت متأخر جدًا ، بالفعل في عملية إصدار هذا الإصدار ، على الرغم من أنه كان موجودًا منذ الإصدار 1.26.0 ، قررنا عدم كسر الروتين وإعداد نسخة ثابتة 1.27.1 ، والتي سيتم إصدارها في المستقبل القريب. بالإضافة إلى ذلك ، إذا لزم الأمر ، الإصدار 1.26.3. يمكن العثور على التفاصيل في ملاحظات الإصدار المقابلة.


ما هو مدرج في الإصدار المستقر 1.27.0


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


SIMD


لذا ، الآن عن المهم: من الآن فصاعدًا ، تتوفر الميزات الأساسية لاستخدام SIMD في Rust! تعني كلمة SIMD "تعليمات مفردة ، دفق بيانات متعددة" (تعليمات مفردة ، بيانات متعددة). النظر في الوظيفة:


 pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { for ((a, b), c) in a.iter().zip(b).zip(c) { *c = *a + *b; } } 

هنا نأخذ شريحتين صحيحين ، ونجمع عناصرها ونضع النتيجة في الشريحة الثالثة. يوضح الكود أعلاه أسهل طريقة للقيام بذلك: تحتاج إلى مراجعة مجموعة العناصر الكاملة ، وتجميعها وحفظ النتيجة. ومع ذلك ، غالبًا ما يجد المترجمون حلاً أفضل. غالبًا ما تقوم LLVM "بتوجيه" رمز مشابه تلقائيًا ، حيث تعني هذه الصياغة المعقدة "تستخدم SIMD". تخيل أن الشرائح a و b تتكون من 16 عنصرًا ، كلاهما. كل عنصر هو u8 ، مما يعني أن الشرائح ستحتوي على 128 بت من البيانات لكل منها. باستخدام SIMD ، يمكننا وضع كل من الشريحتين a و b في تسجيلات 128 بت ، وإضافتها مع تعليمات واحدة ، ثم نسخ 128 بت الناتجة إلى c . سوف تعمل بشكل أسرع!


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


 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "avx2"))] fn foo() { #[cfg(target_arch = "x86")] use std::arch::x86::_mm256_add_epi64; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::_mm256_add_epi64; unsafe { _mm256_add_epi64(...); } } 

هنا نستخدم إشارات cfg لتحديد الإصدار الصحيح من التعليمات البرمجية اعتمادًا على النظام الأساسي الهدف: على x86 سيتم استخدام نسخته الخاصة ، وعلى x86_64 . يمكننا أيضًا الاختيار في وقت التشغيل:


 fn foo() { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { if is_x86_feature_detected!("avx2") { return unsafe { foo_avx2() }; } } foo_fallback(); } 

هنا لدينا نسختان من الوظيفة: يستخدم أحدهما AVX2 - نوع معين من SIMD يسمح لك بتنفيذ عمليات 256 بت. الماكرو is_x86_feature_detected! سينشئ رمزًا يتحقق مما إذا كان المعالج يدعم AVX2 ، وإذا كان الأمر كذلك ، فسيتم استدعاء الوظيفة foo_avx2 . إذا لم يكن الأمر كذلك ، foo_fallback إلى التنفيذ بدون AVX ، foo_fallback . لذا ستعمل الشفرة الخاصة بنا بسرعة كبيرة على المعالجات التي تدعم AVX2 ، ولكنها ستعمل أيضًا على معالجات أخرى ، وإن كان ذلك بشكل أبطأ.


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


 let lots_of_3s = (&[-123.456f32; 128][..]).iter() .map(|v| { 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0 }) .collect::<Vec<f32>>(); 

لاستخدام SIMD في هذا الرمز faster ، تحتاج إلى تغييره على النحو التالي:


 let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter() .simd_map(f32s(0.0), |v| { f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0) }) .scalar_collect(); 

يبدو simd_iter تقريبًا: simd_iter بدلاً من simd_map ، simd_map بدلاً من map ، f32s(2.0) بدلاً من 2.0 . ولكن في النهاية ، تحصل على نسخة معتمدة من SIMD من التعليمات البرمجية الخاصة بك.


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


dyn Trait


في النهاية ، نأسف على البنية المختارة في البداية لكائنات السمات في Rust. كما تتذكر ، بالنسبة إلى Foo يمكنك تحديد كائن سمة مثل هذا:


 Box<Foo> 

ومع ذلك ، إذا كان Foo عبارة عن هيكل ، فهذا يعني ببساطة وضع الهيكل داخل Box<T> . عند تطوير اللغة ، اعتقدنا أن مثل هذه التشابهات ستكون فكرة جيدة ، لكن التجربة أظهرت أن هذا يؤدي إلى الارتباك. وهو ليس فقط Box<Trait> : impl SomeTrait for SomeOtherTrait أيضًا بناء جملة صحيح رسميًا ، لكنك دائمًا ما تحتاج إلى كتابة impl<T> SomeTrait for T where T: SomeOtherTrait بدلاً من ذلك. إنه نفس الشيء مع impl SomeTrait ، الذي يبدو أنه يضيف طرقًا أو تطبيقًا افتراضيًا محتملًا للنوع ، ولكنه في الواقع يضيف أساليبه الخاصة إلى كائن الكتابة. أخيرًا ، مقارنةً impl Trait الجملة impl Trait المُضاف حديثًا ، تبدو بنية Trait أقصر ويفضل استخدامها ، ولكن في الواقع هذا ليس صحيحًا دائمًا.


لذلك ، في Rust 1.27 ، قمنا بتثبيت بنية dyn Trait الجديدة. تبدو كائنات السمات الآن كما يلي:


 //  =>  Box<Foo> => Box<dyn Foo> &Foo => &dyn Foo &mut Foo => &mut dyn Foo 

وبالمثل بالنسبة لأنواع المؤشر الأخرى: Arc<Foo> الآن Arc<dyn Foo> ، إلخ. نظرًا لمتطلبات التوافق مع الإصدارات السابقة ، لا يمكننا إزالة البنية القديمة ، ولكننا أضفنا فحصًا ثابتًا bare-trait-object ، والذي يحل بشكل افتراضي البنية القديمة. إذا كنت تريد حظره ، فيمكنك تنشيط هذا الفحص. اعتقدنا أنه مع تشغيل الشيك بشكل افتراضي ، سيتم عرض الكثير من التحذيرات الآن.


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

#[must_use] للوظائف


في الختام ، تم توسيع تأثير السمة #[must_use] : الآن يمكن استخدامها للوظائف .


في السابق ، تم تطبيقه فقط على الأنواع ، مثل Result <T, E> . ولكن الآن يمكنك القيام بذلك:


 #[must_use] fn double(x: i32) -> i32 { 2 * x } fn main() { double(4); // warning: unused return value of `double` which must be used let _ = double(4); // (no warning) } 

باستخدام هذه السمة ، قمنا أيضًا بتحسين المكتبة القياسية بشكل طفيف : Clone::clone و Iterator::collect و ToOwned::to_owned ستعطي تحذيرات إذا لم تستخدم قيم الإرجاع الخاصة بها ، مما سيساعدك على ملاحظة عمليات باهظة الثمن تتجاهل نتائجها عن طريق الخطأ.


انظر ملاحظات الإصدار لمزيد من التفاصيل.


استقرار المكتبة


تم تثبيت واجهات برمجة التطبيقات الجديدة التالية في هذا الإصدار:



انظر ملاحظات الإصدار لمزيد من التفاصيل.


تحسينات البضائع


تلقت Cargo اثنين من التحسينات الطفيفة في هذا الإصدار. أولاً ، --target-dir ، والذي يمكن استخدامه لتغيير دليل التنفيذ الهدف.


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


لذلك ، 'auto'- Cargo.toml . لا يمكننا إصلاح هذا السلوك دون انهيار محتمل للمشاريع التي تعتمد عليه عن غير قصد. لذلك ، إذا كنت ترغب في تكوين بعض الأهداف ، وليس كلها ، يمكنك تعيين مفتاح autoexamples على true في قسم [package] .


انظر ملاحظات الإصدار لمزيد من التفاصيل.


المطورين 1.27.0


شارك الكثير من الناس في تطوير Rust 1.27. لم نتمكن من إكمال العمل بدون كل واحد منكم.


شكرا لك!


من مترجم: أعرب عن امتناني لأعضاء مجتمع ruRust وأوزكريف شخصيًا لمساعدتهم في الترجمة والتدقيق اللغوي

Source: https://habr.com/ru/post/ar415091/


All Articles