الصدأ لمطوري جافا

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


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


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


الدافع اللغوي


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


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


, Rust ( wasm frontends yew ). , , , , ( ) . .


, , Java Rust :


  • ( GC)
  • ()

; , , . , .




Rust . Rust enum struct. enum — ( , ). enum Java, , Java enum, . enum , , . , , Rust null nil. Rust, .


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

Option, T. T , T. Option 2 , None (" ") , Some T. :


let a = Some("foo".to_string()); //    Option<String>

let b: Option<usize> = Some(1); //    Option<usize>,    

. , . , . , .


Rust enum match. , .


fn plus(a: Option<usize>) -> Option<usize> {
    match a {
        Some(v) => Some(v + 1),
        None => None
   }
}

, . match. cheats.rs match. if/else.


Option, - ( Some ) . , Option , .


fn plus(a: Option<usize>) -> Option<usize> {
    a.map(|v| v + 1)
}

|| {} — . Rust - , , " " .



struct — . , , , .


struct A {
   field: usize
}

"" .


let a: (usize, usize) = (1, 1); //    

.


struct Foo<T> {
    field: T
}


enum struct . , impl . , Rust. struct impl , :


struct Thangs {
   list: Vec<Thang>
}

struct Thang;

impl Thangs {
   // **  `new`    ,   ' '
   fn new() -> Self {
       Self {
           list: vec![]
       }
   }

   fn add_thang(&mut self, thang: Thang) {
       self.list.push(thang);
   }
}

fn main() {
  // ** &mut self   'add_thangs'   mut   
   let mut thangs = Thangs::new();
   thangs.add_thang(Thang);
}

Java, value.method() " ". , &mut self :


let mut thangs = Thangs::new();
Thangs::add_thang(&mut thangs, Thang);

, Rust . enum struct . Java - struct impl , "", ( , ). " Rust ", Java , . Java 14 "Records" () . , Java "", ( , Rust , sum product ). Java, - , , !




Rust . , . . :


struct Thing { field: usize }

fn main() {
    let a = Thing { field: 1 };
    // .. do stuff with a
}

- . , , Sized. , . , ( main) .


Java, new, , .



Box ( stdlib , Rc, Arc ..). , , ? , , , , ( ). , , , , "" Box , .


fn main () {
    let a = Box::new(Thing { field: 1 });
}

, . , . , , a a. usize , .


Box . - Java,


trait Foo {}

struct Thing;

impl Foo for Thing {}

struct OtherThing;

impl Foo for OtherThing {}

fn main () {
    let a: Vec<Box<dyn Foo>> = vec![Box::new(OtherThing), Box::new(Thing)]; //   
    //  ''     ,    
    //            Foo
    }

trait, . , . , . Rust , , , , .


, , . Rust — .


.


enum List<T> {
    Nil,
    Cons((T, List<T>))
}

. List<T> Nil , Cons, . , , ?
?


    error[E0072]: recursive type `List` has infinite size
     --> src/lib.rs:7:1
      |
    7 | enum List<T> {
      | ^^^^^^^^^^^^ recursive type has infinite size
    8 |     Nil,
    9 |     Cons((T, List<T>))
      |          ------------ recursive without indirection
      |
      = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `List` representable

. help . , , . , , , N-? , , ? , . .


, .


enum List<T> {
    Nil,
    Cons((T, Box<List<T>>))
}

. , . .




Java Rust, ( ) :


enum Shape {
    Circle { radius: f32 },
    Rectangle { width: f32, height: f32 },
}

area () , , , :


impl Shape {
    pub fn area(self) -> f32 {
        match self {
            Shape::Circle { radius } => std::f32::consts::PI * radius.powi(2),
            Shape::Rectangle { width, height } => width * height,
        }
    }
 }

Java . Rust pub ( ), ( ). , Rust reference.


. Java Shape Circle Rectangle, area. Rust Java, :


  • Shape:
    • Java: Shape
    • Rust: Shape , ( match , )
  • Shape:
    • Java: "" Shape, ,
    • Rust: impl

' ' (expression problem). . enum Rust / Java. , Rust match enum. : « , ?»


, .


trait Area {
    fn area(self) -> f32; //          ( i32)
}

struct Rectangle {
    width: f32,
    height: f32
}

struct Circle {
    radius: f32
}

impl Area for Rectangle {
    fn area(self) -> f32 {
        self.width * self.height
    }
}

impl Area for Circle {
    fn area(self) -> f32 {
        std::f32::consts::PI * self.radius.powi(2)
    }
}

, Circle Rectangle, perimeter, :


trait Perimeter {
    fn perimeter(self) -> f32;
}

impl Perimeter for Rectangle {
    fn perimeter(self) -> f32 {
        2. * (self.width + self.height)
    }
}
//  ..

. , , "" " ".


fn do_something<T: Perimeter + Area>(shape: T) { //   ,    Perimeter  Area
        unimplemented!() // :   
        //        
    }


Rust . , , Java. , . Java , Rust . , . , , . Future , Iterator IntoIterator for..in, Index [], Add, Sub, Mul . , Add


Add std.


pub trait Add<Rhs = Self> { // 1
    type Output; // 2
    fn add(self, rhs: Rhs) -> Self::Output; // 3
}

Std Add Rhs, Self, .. (1). « » Output (2) add, self ( self) rhs Rhs ( ) , Output (3).


use std::ops::Add;

#[derive(Debug)]
struct Content<T> { // 1
    val: T,
}

impl<T> Add for Content<T> // 2
   where
    T: Add, // 3
{
    type Output = Content<<T as Add>::Output>; // 4
    fn add(self, rhs: Content<T>) -> Self::Output {
        Content {
            val: self.val + rhs.val,
        }
    }
}

fn main() {
    let a = Content { val: 2 };
    let b = Content { val: 5 };
    println!("{:?}", a + b); // Content { val: 7 }
}

Content, T (1). Add , Content Add (2), , Content Add (3). , Output Content Output T, Add (4). , , , . , , . , " " , Rust. , Rust , ( ), .


, Sized , fn foo<T>(t: T) -> T, T: Sized. T: ?Sized, T . .



Java . OO Rust, Java. Java — (subtype polymorphism), Rust — (ad-hoc) . , , , ( <T: Trait> ).


, "" . , enum struct, impl. impl , . , , -. .


Rust . str, String, OsStr, OsString, CString CStr ( - ?). , str String, — . , , ?


&str , &str &String , String Deref<Target=str> ( Target= , Target " "). .


fn foo<S: AsRef<str>>(s: S) {
    unimplemented!()
}

AsRefstdlib. :


trait AsRef<T>
  where
    T: ?Sized,
{
    fn as_ref(&self) -> &T;
}

, T, , &T. foo String,


let a = String::from("stuff");
foo(a);

? , ( ). Rust stdlib.


, . , , . , . Java ( , Java ). Java , . « ». Rust , .



, , . , - . , , . Rust , ! , Rust .


.


: Java Rust


Java , . , . - Java , .. . , , Java , ( Java <T> <T extends Class> ), Java , (type erasure). , Object -. Java, , — . - vtable, .


Rust . foo foo , foo . , foo 4 AsRef<str>, 4 . «». , Rust " ". ( Box), Objectأو نقل جدول افتراضي إذا لم نرغب في ذلك. وتجدر الإشارة إلى أن عيب هذه الطريقة هو حجم الكود النهائي ووقت التجميع. اعتمادًا على عدد المتغيرات المختلفة لوظائفنا وعدد عمليات التنفيذ التي نحتاج إلى إنشائها ، يجب أن يمر المزيد من التعليمات البرمجية عبر LLVM ، مما يزيد من وقت التجميع ويزيد من كمية التعليمات البرمجية التي تم إنشاؤها بالفعل.


اتصالات إيفان كاميرون: mail ، github ، twitter ، linkedIn


تجري مناقشة بطيئة لترجمات Rust في دردشة برقية لترجمات Rust .


All Articles