導航:首頁 > 源碼編譯 > rust的特徵編譯

rust的特徵編譯

發布時間:2022-07-20 08:24:39

① Rust 和 C++ 有哪些優劣

Rust 野心勃勃的想要取代 C++,別人問你們對 Go 怎麼看的時候他們就直接回答我們的目標是 C++,Go 也是個很好的語言balabala。
GitHub Wiki 頁面上有一個簡單的比較 Rust for CXX programmers · rust-lang/rust Wiki · GitHub

最直觀的區別就是 Rust 沒有 C++ 的歷史包袱和 C 包袱,所以一切都能更 clear。還有現代的模塊系統。但如果僅僅如此就僅僅是一個 Better C++。

但是 Rust 有更精細的編譯時檢查,把 C++ 的 RAII 模式進行嚴格的編譯時檢查,做到了編譯時的隱式確定性析構。同時區分了 mut 和非 mut,保護數據的不變性的同時能更適合並發。將類型安全執行到可以達到的極致。(匿名用戶的答案非常棒!)

並且,雖然 C++ 也在不斷吸取函數式特性,但是 Rust 做得更徹底,模式匹配和代數數據類型結合起來的威力誰用誰知道。錯誤處理就用的這種方法,沒有異常,也不像 Go 有額外的返回值。

對泛型的支持很好,而且泛型出錯了編譯器的錯誤信息也很友好,不像 C++ 的模板編程……實際上所有的錯誤信息都很友好,用人話給你說清楚了你遇到了什麼問題,有的時候還能幫你提供修改建議。

同時有模式匹配樣式的宏,在代碼生成的同時保證安全。這個我是聽 @權循真 (upsuper) 說的……他說聲明被一堆宏穿插過來穿插過去,他去 IRC 抱怨別人回復說你去 Servo 組用 Rust 吧,沒有這個問題……

盡管生命期的概念有點費解,但是語言本身的元素並沒有那麼多,不需要學習太多的概念。C++ 中構造函數都有各種細節各種坑我簡直難以想像。只有類似介面的東西,沒有繼承可能對一些人來說很不習慣——但是你真的需要繼承嗎?

Rust 的參與者很多都是資深的 C++ 程序員,是一個很對 C++ 程序員胃口的語言。而且上手也很簡單,常用指針基本都有對應版本。名字空間的 :: 操作符更是熟悉。

② 2020-09-26:請問rust中的&和c++中的&有哪些區別

RUST中的&表示引用

C/CPP中 &表示變數的內存地址,是偏向底層的,C/CPP沒有編譯時變數檢查,所以比較自由

java和Rust在實現多線程編程時的異同

Java的實現
打開Follower.java里的這個函數

這里的Follower.this.invitations就是我們的消息隊列,定義是:private LinkedList<Invitation> invitations;LinkedList不是線性安全的集合,需要我們加同步。具體的同步方法就是函數里寫的,通過Java常見的用wait,notify和notifyall給對象加鎖。
處理並發有wait、notify和notiyall,有興趣的朋友可以去這里了解一下:http://www.importnew.com/16453.html。Follower就是一個等待leader發送invitation,處理並返回結果的過程。
Leader.java
這么一段代碼:

裡面就是Leader發送邀請inv,並等待follower返回結果的大概邏輯,通過對消息體加鎖,是Java傳統的實現多線程並發的方式。還有消費者的消息隊列也會加鎖,在Java里,有個對象叫LinkedBlockingQueue,是不用加鎖就可以put和take的,但在例子里,我們選用了更簡單的LinkedList,也是為了表現一下加鎖的邏輯。
Rust的實現
Leader的結構為:

Follower的結構為:

對於其他語言轉過來的同學,這里的Vec,i32,bool都很好理解,不過裡面出現的Arc和Mutex,Sender,Receiver就是新東西了,上面這4個都是Rust標准庫的東西,也是這次分享要介紹的重點對象,是這4個東西共同實現了消息的生產,傳遞和消費。
下面簡單介紹一下分別是做什麼用的:
Arc<T>實現了sync介面。Sync介面是做什麼呢?權威資料是這么說的:當一個類型T實現了Sync,它向編譯器表明這個類型在多線程並發時沒有導致內存不安全的可能性。
如果看不懂不要緊,我們先看看實際中是怎麼用的:

在這個例子里,我們關注這幾句:
let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
let data = data.clone();
let mut data = data.lock().unwrap();
下面分別解釋一下是做什麼的:
簡單的說Arc::new表明了這是通過clone()方法來使用的,每clone,都會給該對象原子計數+1,通過引用計數的方法來保證對象只要還被其中任何一個線程引用就不會被釋放掉,從而保證了前面說的:這個類型在多線程並發時沒有導致內存不安全的可能性。
如果我們不定義為Arc<>就傳到其他線程使用,編譯器會報:
error: capture of moved value: `data`
data[i] += 1;
我們可以記住clone()就是Arc的用法。
接下來我們看Mutex:
Mutex實現了send介面。同樣,在權威資料里是這么描述的:這個類型的所有權可以在線程間安全的轉移
那我們又是怎麼用Mutex的呢?就是用lock().unwrap()。lock()的作用是獲取對象,如果當前有其他線程正在使用Mutex<T>裡面的T對象時,本線程就會阻塞,從而保證同時只有一個線程來訪問對象,mutex也另外提供了try_lock()的方法,是不阻塞的,只要其他線程被佔用,就返回err,通常Arc和Mutex都是一起使用的。
回到我最原始的題目,Mutex和Arc實現了對象本身的線程共享,但是在線程間如何傳遞這個對象呢?就是靠channel,channel通常是這么定義的let (tx, rx) = mpsc::channel();它會返回兩個對象tx和rx,就是之前我提到的sender和receiver。
在我的Rust實現里,關鍵的語句是以下幾個:
let leaders = (0..leader_cnt).map(|i|
Arc::new(Mutex::new(Leader::new(i,dance_types.len() as i32)))
).collect::<Vec<_>>();
這一句是new一堆leader出來,Arc和Mutex表明leader是可以多線程共享和訪問的。
同樣Follower也是:
let followers = (0..follower_cnt).map(|i|
Arc::new(Mutex::new(Follower::new(i,dance_types.len() as i32,leader_cnt)))
).collect::<Vec<_>>();
接下來這幾句就有點不好理解了。

這里定義了一堆的sender和receiver,其中把他們都作為leader和follower的成員變數存起來。大概意思就是每一個leader都通過sender列表可以發送invitation給所有follower,同時又有單個receiver來接受所有follower發給自己的處理結果inviresult。
同樣follower也是這么做。這樣在之後每一個follower和leader作為一個線程跑起來之後,都能在相互之間建立了一條通信的通道。
這個是和Java實現多線程並發最大的不同之處!Java是通過給對象加鎖,Rust是通過channel轉移對象的所有權,在代碼里,leader發送inv給folloer是下面這一句
match self.senders[*follower_id as usize].lock().unwrap().send(inv){,其中的lock().unwrap()是獲得該leader對該follower的發送通道的所有權,send(inv)就是轉移具體的發送對象invitation所有權了。
這個轉移按照我的理解,應該是內存拷貝。就是在follower接收的時候,let inv = match self.receiver.recv() { ,原來leader裡面的inv在send之後已經是不可訪問了,如果你之後再次訪問了inv,會報use of moved value錯誤,而follower裡面的inv則是在follower的棧里新生成的對象,所以,在Java裡面我只定義了invitation對象,但是在Rust裡面,我要再定義一個InviResult,因為我即使在follower線程裡面填了result欄位,leader線程也不能繼續訪問inv了。所以需要依靠follower再次發送一個invresult給leader,所以整個Rust程序大概就是這么一個思路。
實踐總結
之前我測試比較Java和Rust實現的性能時,由於沒有把調試信息去掉,導致Java比Rust慢很多,特別是那些調試信息都是調用String.format,這是比幾個string相加慢上10倍的方法,兩者都去掉調試信息後,leader和follower都會2000的時候,在我低端外星人筆記本里,性能差別大概是2倍吧,沒我想像中大,Rust的程序整個寫下來比較費力,一方面是對ownership機制不熟,思維沒有轉變過來,另一方面Rust的確需要開發者分部分精力到語法細節上。
編者註:馮總也有一些其它的實踐體會,請參見CSDN對馮耀明的專訪,請戳這里。也可以查看他的個人博客里的總結。
下面摘錄采訪中關於Rust的內容過來:
首先Rust裡面的ownership和lifetime概念真的很酷,就因為這個概念實現無內存泄露,野指針和安全並發。
其次,Rust的語法不簡單,也是有不少坑的,據說Rust的潛在用戶應該是現在的C和C++程序員,他們可能會覺得比較習慣,說不定還 覺得更簡單。由於ownership機制,一些在其他語言能夠跑通的程序在Rust下就要調整實現了,它會改變你寫程序的思維方式。據說一些寫Rust超 過半年的程序員已經愛上它了!
我對Rust感受較深的是下面幾點:
初學者不熟悉ownership機制,會無數次編譯失敗。但一旦編譯成功,那麼程序只剩下邏輯錯誤了。同樣,由於ownership機制,將來在項目里修改Rust代碼將可能是痛苦的過程,因為原來編譯通過的代碼可能加入新功能就編譯不過了,這是我的猜測。
Rust編譯速度慢,不過據說最近每一個Rust新發布的版本編譯速度都比之前的版本提高了30%。
Rust沒有類,有的是結構體加方法,我喜歡這種簡單的概念。
Rust沒有類繼承,只有介面,雖然介面可以提供默認的實現。這樣一來,在大型項目里原來類繼承來重用代碼的效果是否就要用成員變數實例來完成呢?
Rust沒有null,取而代之的是None和Option<T>,也因此,結構體在初始化的時候必須初始化所有欄位。
Rust有我一直很想要的錯誤值返回機制,而不必通過拋異常或者需要每每定義包含結果和錯誤體實現。
Rust用send和sync兩個介面來處理多線程並發,其中Arc<T>和Mutex<T>分別實現了這兩個介面,簡單易用。
Rust目前沒有一個強大的IDE,支持斷點調試,變數監控等。
它跟現在動態語言是兩個截然不同的方向,它適合一些資深的程序員,我倒是覺得有必要有這么一本書,叫《從C++到Rust,你需要改善的20個編程 習慣》,能從實踐上告訴開發者Rust里我們應該遵從什麼樣的編程習慣。Rust未來是否像C那樣流行開來成為新一代的主流語言沒有人能夠知道,但它絕對 是值得你去了解和關注的語言。
進一步的思考:反轉鏈表 - Java和Rust的不同實現
Rust的list應該怎麼定義,譬如反轉列表又是怎麼做呢?
由於ownership的機制和不存在空指針的情況,很多在其他帶GC的語言能夠跑起來的程序在Rust下面就要換一種做法。最近試用Rust的基礎數據結構時,更加加強了我的看法。下面以最原始的鏈表list為例。
在Java中,考慮最基本的鏈表定義
class ListNode {
int val;
ListNode next;

ListNode(int x) {
val = x;
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
sb.append(val);
ListNode pNext = this.next;
while (pNext != null) {
sb.append(",");
sb.append(pNext.val);
pNext = pNext.next;
}
sb.append("]");
return String.format("%s", sb.toString());
}
}
如果我們要反轉鏈表,可以這么做:
public ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
ListNode pNext = head.next;
ListNode pPrevious = null;
while (head != null) {
pNext = head.next;
head.next = pPrevious;
pPrevious = head;
head = pNext;
}
return pPrevious;
}
那如果我們按照一般思維,在Rust里對應的實現就是這樣子的:
struct ListNode{
id :i32,
next :Option<Box<ListNode>>
}
反轉鏈表:
fn reverseList2(head :&mut Option<Box<ListNode>>) -> Option<Box<ListNode>> {
match *head{
None => None,
Some(head) => {
let mut head = Some(head);
let mut pNext = head.unwrap().next;
let mut pPrevious:Option<Box<ListNode>> = None;
while true {
match head {
None =>{break;}
_ =>{}
}
pNext = head.unwrap().next;
head.unwrap().next = pPrevious;
pPrevious = head;
head = pNext;
}
pPrevious
}
}
}
然後編譯,報了以下錯誤:
=》match *head{

ERROR:cannot move out of borrowed content
=》 pNext = head.unwrap().next;
ERROR:cuse of moved value: `head`

這些錯誤就是因為Rust的ownership機制,讓我們無法像Java或者C++里保存臨時變數,特別是在循環里。反復試過各種寫法,都行不通。
最後,換成這么來做
鏈表定義:
use List::*;

enum List {
Cons1(i32, Box<List>),
Nil,
}

// Methods can be attached to an enum
impl List {
#[inline]
fn new() -> List {
Nil
}

#[inline]
fn prepend(self, elem: i32) -> List {
Cons1(elem, Box::new(self))
}

fn len(&self) -> i32 {
match *self {
Cons1(_, ref tail) => 1 + tail.len(),
Nil => 0
}
}

fn stringify(&self) -> String {
match *self {
Cons1(head, ref tail) => {
format!("{}, {}", head, tail.stringify())
},
Nil => {
format!("Nil")
},
}
}
}

fn reverseList(list:List, acc:List ) -> List{
match list{
Cons1(val,tail) => {
reverseList(*tail,acc.prepend(val))
}
Nil => acc
}
}

fn main() {
let mut head = List::new();
let mut i=0;
while i < 10 {
i+=1;
head = head.prepend(i);
}
println!("{:30}",head.stringify());
let result = List::new();
let result = reverseList(head,result);
<span style="white-space:pre"> </span>println!("{:30}",result.stringify());
}
從結果可以看到,鏈表已經實現反轉了。所以在Rust下面,很多做法都要換一下。有人說這就是Rust函數式編程的思維。我但願這種遞歸式的做法不會有溢出。

④ 大家如何評價Rust語言

我用rust正在寫一個區塊鏈項目。

如果不熟悉它的機制,很可能會寫得非常啰嗦。
舉個例子Mutex<RefCell<Rc>>> 這種類型多了會讓人崩潰。

c++很多東西被簡化了, 比如拷貝構造函數變成了Copy trait,移動構造函數自帶。 RAII被rust強推(連lock都是).. 想要用內存不安全的操作需要加unsafe。c++那幾個智能指針變成rust的基本類型了。所有的變數都會有一個所有權,不用智能指針的話,只能用引用(rust叫借用),增加了很多限制。指針什麼的很難看到了(寫起來啰嗦)

惡心的生命周期標注,沒有ide很容易被這個煩死。

沒了容器類, 這個習慣c++的要吐槽。

加了很多函數編程的概念。 比如: arr.to_iter().filter(|x| x.age > 20), 還有模式匹配,高階枚舉,但總體沒有scala ocaml這類強大。

完全編譯時, 極少運行時(有類似c++的typeid),要想用類似java的反射機制就不要想了。 泛型和c++一樣, 基本就是一個文本替換(宏)

常用的功能, 如多線程,日誌,文件,網路等都比c++ std和boost好用很多, 但是功能也沒有那麼強大, 不少功能和c一樣直接在系統內核上封裝了一下,寫起來跟c有點像。

完全拋棄面向對象,和go很像,全是struct。這點真心比c++半吊子面向對象強。

比c++方便最多的地方是有一個模塊管理系統,項目的結構都是訂死的(和sbt有點像),靈活性不強。

目前社區不完善,基本上找不到什麼有用的論壇。debug比較痛苦。

總體覺得是c++的閹割版,寫起來很難像c++一樣放得開。小項目會快那麼一點,畢竟不用寫makefile。

⑤ rust性能到底有多好

這個和c++大同小異。 因為把大量的運行時放到了編譯時。 只不過編譯器優化不夠還達不到c++性能。
其實rust和c++的關系很想scala和java的關系。 rust和c++很多概念甚至庫都是通用的,抽象化方式,比如泛性,多態,可變性,拷貝構造,移動構造,都是一樣的。 你要是寫過c++再來寫rust,就會吐槽原來這個功能也有啊...

運行速度上rust c++ java都是大同小異,io處理上 java甚至比rust還要快。內存消耗rust和c++是一個級別的,都非常低。 另外很多人寫rust喜歡用arc cellref這些只能指針, 其實是給這些變數增加了動態性會導致額外開銷,所以這些特性用多了後,rust性能也不會太高:

⑥ Rust工作台怎麼使用

對准它然後按E 接下來就把裝備放進去,修東西,會需要一些材料。

⑦ 為什麼Rust這樣的語言還需要C/C++編譯器

需要用 VS 的鏈接器,應該是需要支持 FFI 的原因。Windows 是 Rust 承諾要支持的主要平台之一,這意味著,Rust要有能力和Windows上的靜態庫和動態庫來交互。這時候,MSVC的ABI就是繞不過去的一個問題。可以參考 Rustup 的官方文檔對Windows平台的描述,rust-lang-nursery/rustup.rs。 Windows平台上有兩套ABI,一個是MSVC,一個是MinGW。所以你其實有兩個選擇,要麼安裝 msvc,然後
rustup install stable-x86_64-pc-windows-msvc
要麼安裝 MinGW,然後
rustup install stable-x86_64-pc-windows-gnu
在 Rustup 的文檔上有這么一句話 By default rustup on Windows configures Rust to target the 32-bit MSVC ABI, that is the i686-pc-windows-msvc target triple. 所以,默認安裝的話,你需要安裝 msvc。

閱讀全文

與rust的特徵編譯相關的資料

熱點內容
哈夫曼編碼數據壓縮 瀏覽:414
鎖定伺服器是什麼意思 瀏覽:375
場景檢測演算法 瀏覽:607
解壓手機軟體觸屏 瀏覽:338
方舟pv怎麼轉伺服器 瀏覽:99
數據挖掘中誤差值演算法函數 瀏覽:118
php開發套件 瀏覽:190
伺服器的spi板是什麼 瀏覽:896
解壓縮全能王中文密碼是什麼 瀏覽:80
javaftp伺服器上傳文件 瀏覽:103
演算法設計中文版pdf 瀏覽:81
視頻壓縮形式怎麼改 瀏覽:368
perl程序員 瀏覽:789
電子表格對比命令 瀏覽:610
php循環輸出數組內容 瀏覽:750
電腦加密能不能強制關掉 瀏覽:616
趣味單人解壓桌游 瀏覽:212
oppo手機谷歌伺服器無法核實什麼 瀏覽:320
軟體怎麼加密華為 瀏覽:222
掃地機怎麼安裝app 瀏覽:319