هكذا نكتب كود Rust - أمثلة


(مهند الرسيني) #1

السلام عليكم ورحمة الله وربكاته

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

الهدف من الموضوع نشر هذه اللغة والتعريف بمزايا اللغة هذا المجتمع.


نبدأ بمثال عمل خادم باستعمال إطار العمل Actix يستقبل طلبات الـ HTTP على معرف(URI) ال “/users/{name}” ويرد برسالة ترحيب بالاسم الموجود في المعرف

extern crate actix_web;
use actix_web::{http, server, App, HttpRequest, Path, Result};

fn index(name: Path<String>) -> Result<String> {
    Ok(format!("Dear {}, Welcome from Rust!", name))
}

fn main() {
    server::new(|| {
        App::new().resource("/users/{name}", |r| r.method(http::Method::GET).with(index))
    })
    .bind("127.0.0.1:8088")
    .unwrap()
    .run();
}


(سليمان ) #2

هاذي حقت c :face_with_raised_eyebrow: ! هل تؤدي نفس الغرض ؟

ملاحظة …
لاعلم لي بـRust ابداً


(مهند الرسيني) #3

نعم تودي نفس الغرض وهي تعتبر تقطه بداية البرنامج (Entry point) ، إلا أن توقيع/تعريف الدالة يختلف إلى حد ما.

ففي لغة سي يتم تمرير معطيات البرنامج إلى الدالة main بينما في Rust لا يتم ذلك (يمكن الوصول لمعطيات البرنامج بطريقة أخرى).


(مهند الرسيني) #4

مثال آخر لعملية الـ Serialization و الـ Deserializtion في لغة Rust باستعمال المكتبة المشهورة serde.

في المثال قمت بتحويل مصفوفة من النوع Book إلى تنسيق JSON وكذلك Yaml

#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate serde_yaml;

#[derive(Serialize, Deserialize)]
struct Book {
    title: String,
    price: f32,
    author: Vec<String>,
    pages: i32,
    #[serde(skip_serializing_if = "Option::is_none")]
    description: Option<String>,
}

fn main() {
    let rust_book = Book {
        title: "Programming Rust".into(),
        price: 48.05,
        author: vec!["Jim Blandy".into(), "Jason Orenddorff".into()],
        pages: 606,
        description: Some(
            "Rust is a new systems programming language that combines the performance and \
             low-level control of C and C++ with memory safety and thread safety. Rust's modern, \
             flexible types ensure your program is free of null pointer dereferences, double \
             frees, dangling pointers, and similar bugs, all at compile time, without runtime \
             overhead. In multi-threaded code, Rust catches data races at compile time, making \
             concurrency much easier to use."
                .into(),
        ),
    };

    let ddd_book = Book {
        title: "Domain-Driven Design : Tackling Complexity in the Heart of Software".into(),
        price: 64.88,
        author: vec!["Eric Evans".into()],
        pages: 560,
        description: None,
    };

    let books = vec![rust_book, ddd_book];

    println!(
        "Here is the JSON format for these books: \n{}",
        serde_json::to_string_pretty(&books).unwrap()
    );

    println!(
        "Here is the Yaml format for these books: \n{}",
        serde_yaml::to_string(&books).unwrap()
    );
}

وهنا المخرجات بعد تشغيل البرنامج:

~/أعمالي/البرمجة/Rust/learrning_rust $ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/learrning_rust`
Here is the JSON format for these books: 
[
  {
    "title": "Programming Rust",
    "price": 48.05,
    "author": [
      "Jim Blandy",
      "Jason Orenddorff"
    ],
    "pages": 606,
    "description": "Rust is a new systems programming language that combines the performance and low-level control of C and C++ with memory safety and thread safety. Rust's modern, flexible types ensure your program is free of null pointer dereferences, double frees, dangling pointers, and similar bugs, all at compile time, without runtime overhead. In multi-threaded code, Rust catches data races at compile time, making concurrency much easier to use."
  },
  {
    "title": "Domain-Driven Design : Tackling Complexity in the Heart of Software",
    "price": 64.88,
    "author": [
      "Eric Evans"
    ],
    "pages": 560
  }
]
Here is the Yaml format for these books: 
---
- title: Programming Rust
  price: 48.04999923706055
  author:
    - Jim Blandy
    - Jason Orenddorff
  pages: 606
  description: "Rust is a new systems programming language that combines the performance and low-level control of C and C++ with memory safety and thread safety. Rust's modern, flexible types ensure your program is free of null pointer dereferences, double frees, dangling pointers, and similar bugs, all at compile time, without runtime overhead. In multi-threaded code, Rust catches data races at compile time, making concurrency much easier to use."
- title: "Domain-Driven Design : Tackling Complexity in the Heart of Software"
  price: 64.87999725341797
  author:
    - Eric Evans
  pages: 560

(مهند الرسيني) #5

مثال لعمل برنامج ذو واجهة رسومية بسيطة باستعمال مكتبة GTK+.

الواجهة تحتوي على زر يقوم بإظهار نافذة “حول البرنامج” وتلك النافذة تحتوي على بعض المعلومات عن البرنامج

extern crate gio;
extern crate gtk;

use gio::prelude::*;
use gio::{ApplicationExt, ApplicationFlags};

use gtk::prelude::*;
use gtk::{AboutDialog, AboutDialogExt, Application, ApplicationWindow, Button};

fn main() {
    // create GTK application instance
    let application = Application::new("org.MyApp", ApplicationFlags::FLAGS_NONE)
        .expect("Failed to start GTK Application");
    // closure to build the UI when the app starts
    application.connect_startup(move |app| {
        build_ui(app);
    });
    // run the app
    application.run(&[]);
}

// function to build the UI for our app
fn build_ui(app: &Application) {
    // we create window with title
    let window = ApplicationWindow::new(app);
    window.set_title("GTK+ in Rust");
    window.set_border_width(10);
    // we create button with label
    let button = Button::new_with_label("حول البرنامج");
    // we call closure when the button get clicked
    button.connect_clicked(|_button| {
        // we create and show up About dialog
        let about_dlg = AboutDialog::new();
        about_dlg.set_authors(&["مهند الرسيني"]);
        about_dlg.set_comments("مثال على استعمال مكتبة GTK+ لبناء واجهة رسومية ولغة Rust");
        about_dlg.set_license("CC0 - المشاع الإبداعي");
        about_dlg.set_copyright("٢٠١٨ / ١٤٤٠");
        about_dlg.set_version("0.1.0");
        about_dlg.set_website("https://gitlab.com/0x3uh4224d/");
        about_dlg.set_website_label("GitLab - Muhannad Alrusayni");
        about_dlg.set_logo_icon_name("document-page-setup");
        about_dlg.show();
    });
    // adding button to the window
    window.add(&button);
    // showing the window and its content
    window.show_all();
}

هنا عرض سريع للبرنامج


(مهند الرسيني) #6

مثال على الـ Iterator والقوة التي نحصل عليها عندما نتعامل مع الأنواع التي تدعم هذه السمة (Trait)، والمصفوفات من الأنواع التي تدعم هذه السمة.

في هذا المثال لدينا مصفوفة تحتوي على بعض الأسماء ونحن بدورنا سنقوم:

  • بمعرفة طول أطول أسم في المصفوفة، وطباعة الرقم.
  • بالبحث عن الأسماء التي تحتوي على الحرف “ي”، وطباعة الأسماء.

وكذلك مصفوفة أخرى تحتوي على أرقام كتبتها بشكل عشوائي، وسنقوم:

  • بحساب مجموع الأرقام الزوجية، وطباعة المجموع.
  • بالتحقق في ما إذا كانت جميع الأرقام أكبر من صفر، وطباعة النتيجة.

هنا الكود

fn main() {
    let names = [
        "أحمد يوسف",
        "علي محمد",
        "ماجد رائد",
        "عبدالله أحمد",
        "ياسر محمد",
        "يحيى منصور",
        "عبسي",
        "فيصل فهد",
    ];

    // حساب طول أطول اسم بالمصفوفة
    let max_length = names.iter().map(|name| name.chars().count()).max().unwrap();

    println!("اطول اسم: {}", max_length);

    // تصفية الاسماء والحصول على الأسماء التي تحتوي حرف ي
    let names_with_ya: Vec<&&str> = names.iter().filter(|name| name.contains("ي")).collect();

    println!(
        "الاسماء التي تحتوي على الحرف 'ي' هي: {:#?}",
        names_with_ya
    );

    let numbers = [1, 4, 2, 7, -11, 8, 13, 9];

    // حساب مجموع الأعداد الزوجية
    let sum: i32 = numbers.iter().filter(|x| *x % 2 == 0).sum();

    println!("مجموع الأعداد الزوجية هو {}", sum);

    // تحقق ما إذا كانت جميع الأرقام أكبر من صفر
    let result = numbers.iter().all(|&x| x > 0);

    println!("جميع الأعداد أكبر من صفر: {}", result);
}

ونتيجة تنفيذ البرنامج:

    Finished dev [unoptimized + debuginfo] target(s) in 0.01s
     Running `/home/muhannad/البرمجة/Rust/learrning_rust/target/debug/learrning_rust`
اطول اسم: 12
الاسماء التي تحتوي على الحرف 'ي' هي: [
    "أحمد يوسف",
    "علي محمد",
    "ياسر محمد",
    "يحيى منصور",
    "عبسي",
    "فيصل فهد"
]
مجموع الأعداد الزوجية هو 14
جميع الأعداد أكبر من صفر: false

ربما لاحظت أننا لم نستعمل أي تعليمه من تعلمات الحلقات (for, loop, while…) وذلك لأن جميع ما نريده من تعليمات الحلقات متوفر في سمة الـ Iterator.

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

هذا مثال موجز جداً عن ما تتيحه لنا السمة Iterator، ألقي نظرة على الوثائق الخاصة بهذه السمة لتجد بعض الأمثلة ووثائق الدوال.