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, Optional
Typen 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 :
; , , . , .
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());
let b: Option<usize> = Some(1);
. , . , . , .
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 {
fn new() -> Self {
Self {
list: vec![]
}
}
fn add_thang(&mut self, thang: Thang) {
self.list.push(thang);
}
}
fn main() {
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 };
}
- . , , 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)];
}
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;
}
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) {
unimplemented!()
}
Rust . , , Java. , . Java , Rust . , . , , . Future
, Iterator
IntoIterator
for..in
, Index
[]
, Add
, Sub
, Mul
. , Add
Add
std.
pub trait Add<Rhs = Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
Std Add
Rhs
, Self
, .. (1). « » Output
(2) add
, self
( self
) rhs
Rhs
( ) , Output
(3).
use std::ops::Add;
#[derive(Debug)]
struct Content<T> {
val: T,
}
impl<T> Add for Content<T>
where
T: Add,
{
type Output = Content<<T as Add>::Output>;
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
, 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!()
}
AsRef
— stdlib. :
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
oder ü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 .