10 فوائد غير واضحة لاستخدام الصدأ

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



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


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


1. شمولية اللغة


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


دعونا نلقي نظرة على بعض الأمثلة البسيطة لاستخدام Rust.


مثال على دمج مكررين في مكرر واحد على أزواج من العناصر:


let zipper: Vec<_> = (1..).zip("foo".chars()).collect(); assert_eq!((1, 'f'), zipper[0]); assert_eq!((2, 'o'), zipper[1]); assert_eq!((3, 'o'), zipper[2]); 

اركض


ملاحظة: استدعاء name!(...) التنسيق name!(...) هو استدعاء لماكرو وظيفي. تنتهي أسماء وحدات الماكرو في Rust دائمًا برمز ! بحيث يمكن تمييزها عن أسماء الوظائف والمعرفات الأخرى. سيتم مناقشة فوائد استخدام وحدات الماكرو أدناه.

مثال على استخدام مكتبة regex الخارجية للعمل مع التعبيرات العادية:


 extern crate regex; use regex::Regex; let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); assert!(re.is_match("2018-12-06")); 

اركض


مثال على تنفيذ Add لبنية Point الخاصة بها لزيادة التحميل على عامل الإضافة:


 use std::ops::Add; struct Point { x: i32, y: i32, } impl Add for Point { type Output = Point; fn add(self, other: Point) -> Point { Point { x: self.x + other.x, y: self.y + other.y } } } let p1 = Point { x: 1, y: 0 }; let p2 = Point { x: 2, y: 3 }; let p3 = p1 + p2; 

اركض


مثال على استخدام نوع عام في هيكل:


 struct Point<T> { x: T, y: T, } let int_origin = Point { x: 0, y: 0 }; let float_origin = Point { x: 0.0, y: 0.0 }; 

اركض


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


2. أدوات بناء وإدارة تبعية مريحة


من الواضح أنه لم يتم الإعلان عن ذلك ، ولكن يلاحظ الكثير أن Rust لديها أحد أفضل أنظمة إدارة البناء والتبعية المتاحة اليوم. إذا كنت مبرمجًا في C أو C ++ ، وكانت مسألة الاستخدام غير المؤلم للمكتبات الخارجية حادة للغاية بالنسبة لك ، فإن استخدام Rust مع أداة البناء ومدير تبعية الشحن سيكون خيارًا جيدًا لمشاريعك الجديدة.


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


يستخدم ملف تهيئة Cargo لغة الترميز الودية والحد الأدنى لوصف إعدادات المشروع. فيما يلي مثال Cargo.toml تكوين Cargo.toml النموذجي:


 [package] name = "some_app" version = "0.1.0" authors = ["Your Name <you@example.com>"] [dependencies] regex = "1.0" chrono = "0.4" [dev-dependencies] rand = "*" 

وفيما يلي ثلاثة أوامر نموذجية لاستخدام Cargo:


 $ cargo check $ cargo test $ cargo run 

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


3. الاختبارات المدمجة


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


 pub fn is_false(a: bool) -> bool { !a } pub fn add_two(a: i32) -> i32 { a + 2 } #[cfg(test)] mod test { use super::*; #[test] fn is_false_works() { assert!(is_false(false)); assert!(!is_false(true)); } #[test] fn add_two_works() { assert_eq!(1, add_two(-1)); assert_eq!(2, add_two(0)); assert_eq!(4, add_two(2)); } } 

اركض


الوظائف في وحدة test ، المميزة بسمة #[test] ، هي اختبارات وحدة. سيتم تنفيذها بالتوازي عندما يتم استدعاء أمر cargo test . إن سمة #[cfg(test)] الشرطي #[cfg(test)] ، التي تحدد الوحدة بأكملها باختبارات ، ستؤدي إلى حقيقة أن الوحدة النمطية سيتم تجميعها فقط عند تنفيذ الاختبارات ، ولن تدخل في التجميع العادي.


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


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


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


4. توثيق جيد مع الأمثلة الحالية


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


 /// Returns a byte slice of this `String`'s contents. /// /// The inverse of this method is [`from_utf8`]. /// /// [`from_utf8`]: #method.from_utf8 /// /// # Examples /// /// Basic usage: /// /// ``` /// let s = String::from("hello"); /// /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { &self.vec } 

التوثيق


فيما يلي مثال على استخدام طريقة as_bytes من النوع String


 let s = String::from("hello"); assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes()); 

سيتم تنفيذه كاختبار أثناء إطلاق الاختبارات.


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


5. خصم تلقائي ذكي للأنواع


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


 let mut vec = Vec::new(); let text = "Message"; vec.push(text); 

اركض


إذا قمنا بترتيب نوع التعليقات التوضيحية ، فسيبدو هذا المثال كما يلي:


 let mut vec: Vec<&str> = Vec::new(); let text: &str = "Message"; vec.push(text); 

أي ، لدينا متجه لشرائح السلسلة ومتغير من نوع شريحة السلسلة. ولكن في هذه الحالة ، يعد تحديد الأنواع متكررًا تمامًا ، حيث يمكن للمترجم إخراجها بنفسها (باستخدام النسخة الموسعة من خوارزمية Hindley-Milner ). حقيقة أن vec هو ناقل واضح بالفعل من خلال نوع القيمة Vec::new() من Vec::new() ، ولكن لم يتضح بعد نوع عناصره. حقيقة أن نوع text هو شريحة سلسلة أمر مفهوم من خلال حقيقة أنه تم تعيين حرفيا من هذا النوع. وهكذا ، بعد vec.push(text) ، يصبح نوع عناصر المتجه واضحًا. لاحظ أن نوع متغير vec تم تحديده بالكامل من خلال استخدامه في سلسلة التنفيذ ، وليس في مرحلة التهيئة.


يزيل مثل هذا النظام من نوع الاستدلال الضوضاء من التعليمات البرمجية ويجعلها موجزة مثل التعليمات البرمجية في بعض لغات البرمجة المكتوبة ديناميكيًا. وهذا مع الحفاظ على كتابة ثابتة صارمة!


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


6. مطابقة النمط عند نقاط التصريح المتغيرة


let العملية


 let p = Point::new(); 

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


 let Point { x, y } = Point::new(); 

اركض


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


 let [a, b, _] = [1, 2, 3]; 

وأكثر من ذلك بكثير. الشيء الأكثر بروزًا هو أن مثل هذه المقارنات يتم إجراؤها في جميع الأماكن حيث يمكن إدخال أسماء متغيرات جديدة في Rust ، وهي: في match ، let ، if let ، while let if let ، في رأس حلقة for ، في الحجج الخاصة بالوظائف والإغلاق. في ما يلي مثال على استخدام الأنماط المتطابقة في حلقة للتكرار:


 for (i, ch) in "foo".chars().enumerate() { println!("Index: {}, char: {}", i, ch); } 

اركض


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


مثال شائع آخر على استخدام نمط في حلقة for :


 for _ in 0..5 { //   5  } 

هنا نتجاهل ببساطة قيمة المكرر باستخدام النمط _ . لأننا لا نستخدم رقم التكرار في نص الحلقة. يمكن فعل الشيء نفسه ، على سبيل المثال ، بحجة دالة:


 fn foo(a: i32, _: bool) { //      } 

أو عند المطابقة في عبارة match :


 match p { Point { x: 1, .. } => println!("Point with x == 1 detected"), Point { y: 2, .. } => println!("Point with x != 1 and y == 2 detected"), _ => (), //        } 

اركض


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


7. تمديد بناء الجملة و DSL مخصص


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


 println!("Hello, {name}! Do you know about {}?", 42, name = "User"); 

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


 let name = "Bob"; let result = js! { var msg = "Hello from JS, " + @{name} + "!"; console.log(msg); alert(msg); return 2 + 2; }; println!("2 + 2 = {:?}", result); 

js! الماكرو js! محدد في حزمة stdweb ويسمح لك بتضمين شفرة جافا سكريبت كاملة في برنامجك (باستثناء السلاسل أحادية الاقتباس والعوامل غير المكتملة بفاصلة منقوطة) واستخدام كائنات من شفرة Rust باستخدام بناء الجملة @{expr} .


تقدم وحدات الماكرو فرصًا هائلة لتكييف بنية برامج Rust مع المهام المحددة لمجال معين. سيوفر وقتك واهتمامك عند تطوير التطبيقات المعقدة. ليس عن طريق زيادة وقت التشغيل ، ولكن عن طريق زيادة وقت التجميع. :)


8. التوليد التلقائي للشفرة التابعة


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


 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] struct Point { x: i32, y: i32, } 

نظرًا لأن جميع هذه الأنواع ( Copy و Clone و Debug و Default و PartialEq و PartialEq ) من المكتبة القياسية يتم تنفيذها لنوع حقول بنية i32 ، يمكن عرض تنفيذها تلقائيًا للبنية بأكملها ككل. مثال آخر:


 extern crate serde_derive; extern crate serde_json; use serde_derive::{Serialize, Deserialize}; #[derive(Serialize, Deserialize)] struct Point { x: i32, y: i32, } let point = Point { x: 1, y: 2 }; //  Point  JSON . let serialized = serde_json::to_string(&point).unwrap(); assert_eq!("{\"x\":1,\"y\":2}", serialized); //  JSON   Point. let deserialized: Point = serde_json::from_str(&serialized).unwrap(); 

اركض


هنا ، باستخدام Deserialize and Deserialize من مكتبة serde لبنية Point ، يتم إنشاء طرق تسلسلها serde تسلسلها تلقائيًا. بعد ذلك ، يمكنك تمرير مثيل من هذه البنية إلى العديد من وظائف التسلسل ، على سبيل المثال ، تحويلها إلى سلسلة JSON.


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


9. نوع البيانات الجبرية


ببساطة ، نوع البيانات الجبرية هو نوع بيانات مركب هو اتحاد الهياكل. بشكل أكثر رسمية ، هو نوع من أنواع المنتجات. في الصدأ ، يتم تعريف هذا النوع باستخدام الكلمة enum :


 enum Message { Quit, ChangeColor(i32, i32, i32), Move { x: i32, y: i32 }, Write(String), } 

يمكن أن يكون نوع قيمة معينة لمتغير من نوع Message واحدًا فقط من أنواع البنية المدرجة في Message . هذا إما هيكل Quit بدون حقل شبيه بالوحدة ، أو أحد هياكل ChangeColor أو Write مجموعة tuple مع حقول مجهولة الاسم ، أو بنية Move المعتادة. يمكن تمثيل نوع تعداد تقليدي كحالة خاصة لنوع بيانات جبري:


 enum Color { Red, Green, Blue, White, Black, Unknown, } 

من الممكن معرفة النوع الذي أخذ قيمة بالفعل في حالة معينة باستخدام مطابقة الأنماط:


 let color: Color = get_color(); let text = match color { Color::Red => "Red", Color::Green => "Green", Color::Blue => "Blue", _ => "Other color", }; println!("{}", text); ... fn process_message(msg: Message) { match msg { Message::Quit => quit(), Message::ChangeColor(r, g, b) => change_color(r, g, b), Message::Move { x, y } => move_cursor(x, y), Message::Write(s) => println!("{}", s), }; } 

اركض


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


 pub enum Option<T> { None, Some(T), } 

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


 fn divide(numerator: f64, denominator: f64) -> Option<f64> { if denominator == 0.0 { None } else { Some(numerator / denominator) } } let result = divide(2.0, 3.0); match result { Some(x) => println!("Result: {}", x), None => println!("Cannot divide by 0"), } 

اركض


نوع البيانات الجبرية هو أداة قوية ومعبرة تفتح الباب أمام تطوير مدفوع بالنوع. يعين برنامج مكتوب بكفاءة في هذا النموذج معظم عمليات التحقق من صحة عمله لنظام النوع. لذلك ، إذا كنت تفتقر إلى القليل من Haskell في البرمجة الصناعية اليومية ، يمكن أن يكون Rust هو منفذك. :)


10. إعادة بيع ديون سهلة


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




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

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


All Articles