Rost für Java-Entwickler

Ich präsentiere eine Übersetzung eines Artikels von Evan Cameron , der Java-Entwicklern helfen kann, die Unterschiede und Ähnlichkeiten zwischen den beiden Sprachen besser zu verstehen - das Original befindet sich auf der Website des Autors . Da ich mich nicht als erfahrenen Rust-Entwickler betrachte, ist es unwahrscheinlich, dass ich angemessen an möglichen Diskussionen teilnehmen kann.


Ich möchte Änderungen am Blog vornehmen und sensiblere Themen belassen, um mich auf sie zu konzentrieren. Vielleicht ist eines der wichtigsten Themen, die in der Rust-Community erledigt werden können, die Schulung neuer Entwickler. Ich dachte über den besten Ansatz nach, um Rust für diejenigen zu unterrichten, die es gewohnt sind, mit Java zu arbeiten und die Sprache für ein neues Projekt zu beherrschen.


Java war eine Sprache, die ich an der Universität studiert habe, daher ist meine Erfahrung damit etwas anachronistisch und ich habe keine wirklichen Versuche unternommen, mit der Sprache Schritt zu halten. Als ich Java das letzte Mal schrieb, musste man, wenn man eine Funktion als Argument übergeben wollte, eine neue Schnittstelle deklarieren oder die Funktion einschließen Callable<T>. Seitdem hat Java einen langen Weg zurückgelegt. Dies sind hinzugefügte Funktionen, die einen deutlichen Einfluss auf die funktionale Programmierung haben. Ich spreche von Lambdas, OptionalTypen usw. In diesem Artikel wird nicht darüber gesprochen, wie man in Rust schreibt oder dass Sie Ihren gesamten Java-Code wegwerfen müssen. Java ist eine großartige Sprache mit realen Anwendungsfällen. Ich möchte einige Vergleiche zwischen Java und Rust für einen Anfänger-Rust-Programmierer anstellen.


Sprachmotivation


Zuerst über die Ziele jeder Sprache. Java wurde entwickelt, um viele Probleme zu lösen. Es musste „einfach, objektorientiert und modular“ sein , in einer virtuellen Maschine arbeiten, auf verschiedene Architekturen portierbar sein und eine hohe Leistung aufweisen. Rusts Ziel ist es, „unglaublich schnell und speichereffizient“ zu sein , über ein „Rich-Type-System, Speichersicherheit, Thread-Sicherheit“ zu verfügen, gute Fehlermeldungen zu generieren und einen integrierten Paketmanager zu haben.


. Rust , , . , Rust , . , , , , ( ) , (embedded) . , Rust. Rust , , (dangling) .


, 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), Objectoder übertragen Sie eine virtuelle Tabelle, wenn wir dies nicht möchten. Es ist zu beachten, dass der Nachteil dieser Methode die endgültige Codegröße und die Kompilierungszeit ist. Abhängig davon, wie viele verschiedene Varianten unserer Funktionen und wie viele Implementierungen generiert werden müssen, muss mehr Code durch LLVM geleitet werden, was die Kompilierungszeit und die Menge des tatsächlich generierten Codes erhöht.


Kontakte Evan Cameron: Mail , Github , Twitter , LinkedIn


Eine langsame Diskussion der Rust-Übersetzungen findet in einem Telegramm-Chat für Rust-Übersetzungen statt .


All Articles