يسر فريق تطوير 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
الجديدة. تبدو كائنات السمات الآن كما يلي:
وبالمثل بالنسبة لأنواع المؤشر الأخرى: 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);
باستخدام هذه السمة ، قمنا أيضًا بتحسين المكتبة القياسية بشكل طفيف : 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 وأوزكريف شخصيًا لمساعدتهم في الترجمة والتدقيق اللغوي