Rust pour les développeurs Java

Je présente une traduction d'un article d' Evan Cameron , qui peut aider les développeurs Java à mieux comprendre les différences et les similitudes entre les deux langues - l' original est sur le site de l'auteur . Ne me considérant pas comme un développeur Rust expérimenté, il est peu probable que je puisse raisonnablement participer à d'éventuelles discussions.


Je voudrais apporter des modifications au blog et laisser des sujets plus sensibles pour me concentrer sur eux. Peut-être l'un des sujets les plus importants qui peuvent être traités dans la communauté Rust est la formation de nouveaux développeurs. Je réfléchissais à la meilleure approche pour enseigner Rust à ceux qui ont l'habitude de travailler avec Java et aider à maîtriser le langage pour un nouveau projet.


Java était une langue que j'ai étudiée à l'université, donc mon expérience avec elle est quelque peu anachronique et je n'ai fait aucune tentative réelle pour suivre la langue. La dernière fois que j'ai écrit Java, si vous vouliez passer une fonction en argument, vous deviez déclarer une nouvelle interface ou envelopper la fonction Callable<T>. Depuis lors, Java a parcouru un long chemin. Ce sont des fonctions ajoutées qui ont un effet clair de la programmation fonctionnelle. Je parle de lambdas, de Optionaltypes, etc. Cet article ne parlera pas de la façon d'écrire dans Rust ou de la nécessité de jeter tout votre code Java. Java est un excellent langage avec des cas d'utilisation réels. Je veux faire des comparaisons de Java et de Rust pour un programmeur débutant de Rust.


Motivation linguistique


Tout d'abord sur les objectifs de chaque langue. Java a été créé pour résoudre de nombreux problèmes. Il devait être «simple, orienté objet et modulaire» , il devait fonctionner dans une machine virtuelle, être portable sur différentes architectures, et il devait avoir de hautes performances. Les objectifs de Rust sont d'être «incroyablement rapides et efficaces en mémoire» , d'avoir un «système de type riche, une sécurité de la mémoire, un thread-safe», de générer de bons messages d'erreur et d'avoir un gestionnaire de paquets intégré.


. 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), Objectou transférer une table virtuelle si nous n'en voulons pas. Il convient de noter que l'inconvénient de cette méthode est la taille finale du code et le temps de compilation. Selon le nombre de variantes différentes de nos fonctions et le nombre d'implémentations que nous devons générer, plus le code doit passer par LLVM, augmentant le temps de compilation et augmentant la quantité de code réellement généré.


Contacts Evan Cameron: mail , github , twitter , LinkedIn


Une discussion lente sur les traductions de Rust a lieu dans une discussion par télégramme pour les traductions de Rust .


All Articles