Java程式設計師學習Rust程式設計 - infoworld

banq發表於2022-03-07

如果您是 Java 開發人員,您會發現 Rust 相對容易掌握,這要歸功於這兩種語言的相似性。

根據Stack Overflow的調查,Rust 已經在語言流行度或最常用語言的階梯上攀升,但最引人注目的是,Rust 不斷成為“最受喜愛的語言” 。這證明了使用 Rust 的豐富經驗。
 
Rust 語法
像 Java 一樣,Rust 也是編譯好的。它被編譯為LLVM規範,在精神上類似於JVM,允許輸出到各種目標平臺。

和 Java 一樣,Rust 起源於 C 血統。它在塊中使用花括號,在行終止時使用分號,這與 Java 完全相同。例如,您可以在這裡看到一個簡單的程式,如:

fn main () {     println !( "Hello, InfoWorld!" ); } 

請注意,有一個main()函式,類似於 Java 中的main函式入口點。
 

Rust中的函式
函式在Rust中是獨立的,它們可以在任何地方宣告,包括巢狀在其他函式中。
這與Java不同,在Java中,函式總是被宣告為物件的方法(除了lambdas的情況)。
換句話說,在Java中,所有東西都是一個物件。在Rust中則不然。

fn main() {
    println!("Hello, world!");

    fn function2(){
        println!("Hello InfoWorld");
    }
    function2();

    function3();
}

fn function3() {
    println!("Hello again.");
}


 

隱式返回值
與Java不同,Rust允許你在函式的結尾跳過返回return關鍵字。函式中的最後一條語句將自動被評估為返回值。
這樣做時,你可以省略最後語句中的分號。
 

lambdas程式碼
和Java一樣,Rust支援功能式編碼的lambdas。語法是不同的,但如果你熟悉Java流API,就不難理解。
專案顯示了使用map()函式使一組字串大寫的情況。正如你所看到的,這與Java很相似。

// Rust
fn main() {
    let animals = ["dog", "badger", "quokka"];

    let result = animals.iter().map(|value| value.to_uppercase());

    for animal in result {
        println!("Uppercased: {}", animal);
    }
}


map()函式需要一個兩部分的引數:
  1. 第一部分是管道字元裡面的一個變數,|value|,它將定義作為每個專案的控制程式碼的變數。
  2. 第二部分是要執行的操作。在本例中,我們對陣列的每個元素呼叫to_uppercase()。

注意,像Java一樣,Rust的lambdas是捕獲周圍塊的狀態的閉包。
換句話說,它們可以訪問它們所執行的變數上下文。
  

物件是Rust中的struct
下面程式碼介紹了struct關鍵字。struct是結構的簡稱,它允許你定義一個資料容器,就像Java中類的狀態部分。

struct Animal {
  name: String
}
fn main() {
  let dog = Animal{
    name: String::from("Shiba")
  };
  println!("{}", dog.name);
}

你在struct的大括號內定義結構的成員。這些變數類似於公共成員。

請注意,在你宣告dog變數的那一行,沒有必要呼叫new關鍵字。
Rust可以從上下文中推斷出,但是一個新的引用變數名是有必要的。

接下來,注意到變數名在建立時被設定為一個帶值的字串。這是透過呼叫內建的String.from方法,使用雙冒號引用運算子完成的。

最後,注意到就像Java一樣,Rust使用點運算子來訪問dog例項的名字欄位:dog.name。
 

方法
您可以向struct新增函式,這些函式的行為方式與Java中的方法基本相同。
例如,為了給上述程式碼中所示的Animal struct新增一個speak()方法,你可以使用impl關鍵字。

impl Animal {
  fn speak(&self) {
      println!("{}", self.name);
  }
}

Impl意味著實現介面或父類。
上述程式碼我們正在實現Animal struct:我們定義了一個方法speak,它需要一個引數。
這個引數是特殊的&self指標(Rust中的&意味著引數是一個引用指標)。
這個特殊指標的語義與Java中的this關鍵字非常相似。它指的是當前活動的物件例項。

呼叫dog.speak()將輸出當前例項化物件的名稱。
在這個例子中輸出結果是 "Shiba"。
 

Rust中的可變性
如果你有Java背景,那麼Rust的一個比較奇怪的地方就是變數的預設不可變性。
簡而言之,當你在Rust中宣告一個變數時,它預設是不可變的,試圖改變它將導致一個錯誤。

要使一個變數可變,必須新增mut關鍵字,但mut一次只能由一個引用新增。
記住,Rust高度關注保持程式碼的執行緒安全。這也避免了在Java中看到的併發修改錯誤。

下面程式碼顯示瞭如何使dog物件變異,然後給它分配一個新的名字。

let mut dog = Animal{
  name: String::from("Shiba")
};
dog.name = String::from("Suki");
println!("{}", dog.name);


 

Rust中的型別推理
在Rust中,你並不總是需要告訴編譯器你正在宣告什麼型別的變數。
對於來自Java的開發者來說,這似乎很奇怪,因為在Java中沒有推斷變數型別的工具。
例如,下面程式碼編譯器正確地將型別推斷為整數。

let number1 = 10;
let number2 = 10;
println!("{}", number1 * number2);



 

陰影Shadowing和變數名
另一個可能會讓Java開發者感到驚訝的Rust特性是所謂的變數陰影shadowing。
從本質上講,你可以在一個變數上面建立一個同名的可變變數“罩子”,而不是把它宣告為可變的。

這是一種一次性的可變性,為相同的變數名稱建立一個新的空間。
一般來說,重複使用同一變數名的能力與Java不同。
下面顯示了一個變數陰影的簡單例子。

fn main() {
    let x = 5;
    let x = x + 1;
    println!("The value of x is: {}", x); // outputs 6
}

 

Rust中的元組型別
Rust支援元組型別,它是一種複合變數,在Java中沒有真正的類似物。
下面程式碼向你展示了一個元組的例項。

fn main() {
    let myTuple = ("Sum", 10, 5);
    let (x, y) = myTuple ;
    println!("The {} is: {}", x, y + z);
}


在這裡你可以看到myTuple變數是用括號宣告的,包含三個值、一個字串和兩個整數。這就是一個元組。

你可以將元組 "去結構化(解構或析構) "為元組變數,就像在上面程式碼中看到的那樣,let關鍵字被用來用元組中的值填充每個變數x、y和z。

你也可以透過索引訪問元組成員。例如,tup.0引用元組的第一個欄位(字串 "Sum")。
 

Rust中的traits和泛型
在Rust中,有一個traits的概念,它類似於Java中的“介面interface”。它們定義了一個型別與其他型別共享的屬性。
換句話說,traits抽象了不同型別的共同功能。

Rust中的泛型與Java中的泛型類似,使用類似的角括號語法,根據型別的共享屬性,以一般的方式處理型別。

pub trait Summary {
    fn summarize(&self) -> String;
}
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
}

fn main() {
    let tweet = Tweet {
        username: String::from("dog_post"),
        content: String::from("A Shih Tzu is smaller than a Lurcher",
        ),
        reply: false,
        retweet: false,
    };

    println!("1 new tweet: {}", tweet.summarize());
}


在這裡,trait關鍵字被用來定義一個Summary屬性,然後用impl關鍵字為每個struct物件型別(NewsArticle和Tweet)實現這個屬性。
所以這與Java中的介面非常相似,只是在Java中,介面定義了整個類的表面,而不是零散地定義方法。

相關文章