自從我學(xué)了Rust,就開始了受虐之旅,連編譯都沒成功過(guò)!
張大胖被別人安利了一個(gè)新的語(yǔ)言:Rust,作為編程語(yǔ)言的狂熱愛好者,他自然要嘗試一番。
第一個(gè)程序自然是hello world,太簡(jiǎn)單了,都懶得去寫,看看就行了:
- fn main() {
- println!("hello world");
- }
張大胖原來(lái)用過(guò)C語(yǔ)言, 當(dāng)時(shí)覺得非常不爽的是它本身沒有內(nèi)置常用的數(shù)據(jù)結(jié)構(gòu),比如一個(gè)可以動(dòng)態(tài)增長(zhǎng)的數(shù)組,這Rust怎么樣呢?
- fn main() {
- let v = Vec::new(); //創(chuàng)建了一個(gè)數(shù)組
- v.push(4); // 向數(shù)組添加一個(gè)元素
- }
張大胖寫下let就意識(shí)到,這里是將值(數(shù)組)綁定到變量v , 應(yīng)該是借鑒了Lisp的模式匹配,可以預(yù)見將來(lái)會(huì)遇到這樣的代碼:
- let (name,age) = ("Andy", 30);
還有就是這Rust具備自動(dòng)類型推斷能力,這點(diǎn)挺不錯(cuò)的。
編譯吧!咦,居然失敗了,錯(cuò)誤信息是:cannot borrow `v` as mutable, as it is not declared as mutable
Rust編譯器:我們把對(duì)象分為可變的和不可變的,對(duì)于不可變的,一旦創(chuàng)建以后,就不能再改了。那就加個(gè)關(guān)鍵字mut,讓它變成可變的就可以了:let mut v = Vec::new()
張大胖想起了《effective java》中的一條實(shí)踐:把可變性限制到最小。他嘴里咕噥著:“嗯,Rust默認(rèn)是不可變,這個(gè)思路也許是對(duì)的。”
所有權(quán)
他又探索著寫下一些代碼:
- fn main() {
- //用另外一種方式創(chuàng)建了一個(gè)可變Vector
- let mut v = vec![1,2];
- let v1 = v;
- println!(" the 1st element is {}",v[0]);
- }
編譯,又失敗了,WTF!到底是怎么回事?這么簡(jiǎn)單的程序也會(huì)出錯(cuò)?!
Rust編譯器:誰(shuí)讓你手賤!加了一行代碼:let v1 = v
張大胖:這有什么關(guān)系?在Java中,這就相當(dāng)于對(duì)同一個(gè)對(duì)象,又添加了一個(gè)引用而已!
Rust編譯器:那是Java,在我Rust這里,你一定要放下Java的執(zhí)念!要理解一下所有權(quán)的問(wèn)題。
張大胖:什么所有權(quán)?
Rust編譯器:對(duì)于任何給定的對(duì)象都只有一個(gè)綁定與之對(duì)應(yīng)。你用let mut v = Vec::new()就意味著 v 和這個(gè)Vector對(duì)象綁定了!現(xiàn)在v擁有這個(gè)對(duì)象的所有權(quán)。這一行代碼 let v1 = v ,讓所有權(quán)發(fā)生轉(zhuǎn)移了, 現(xiàn)在v1是新主人了。v就不能再訪問(wèn)這個(gè)Vector, 我把這種情況叫做“轉(zhuǎn)移語(yǔ)義”。
碼農(nóng)翻身注:實(shí)際上, Rust也支持Copy語(yǔ)義,這里不在詳述。
張大胖不滿地說(shuō):這不是徒增煩惱嗎?那我要是把v傳遞給另外一個(gè)函數(shù)呢?
- fn main() {
- let mut v = vec![1,2,3,4]; //創(chuàng)建了一個(gè)可變Vector
- print_vector(v);
- println!(" the 1st element is {}",v[0]);
- }
- fn print_vector(v: Vec<i32>){
- for i in v {
- println!("{}", i);
- }
- }
編譯還是出錯(cuò)!
Rust編譯器:這和剛才是一個(gè)道理,v的所有權(quán)在傳遞給函數(shù)時(shí),被拿走了,所以在main中不能再訪問(wèn)v了 !
借用
張大胖:太變態(tài)了,我就是想在調(diào)用print_vector以后想訪問(wèn)再訪問(wèn)變量v,該怎么辦?
Rust編譯器: 你可以把所有權(quán)暫時(shí)借用(&v)給print_vector,等函數(shù)返回就可以接著使用了。
- fn main() {
- let mut v = vec![1,2,3,4]; //創(chuàng)建一個(gè)可變Vector
- print_vector(&v);
- println!(" the 1st element is {}",v[0]);
- }
- fn print_vector(v: &Vec<i32>){
- ......
- }
這個(gè)借用就相當(dāng)于Java語(yǔ)言的引用了,張大胖想,print_vector函數(shù)已經(jīng)“借到”所有權(quán),應(yīng)該可以為所欲為了吧,于是在函數(shù)內(nèi)做了修改:
- fn print_vector(v: &Vec<i32>) {
- v.push(3);
- .....
- }
再次編譯,再次失敗!張大胖感覺到要吐血了,這Rust實(shí)在太不講道理了。
Rust編譯器:“你這個(gè)借用想要改變?cè)瓉?lái)的對(duì)象,也得加上 &mut才行!”
- fn main() {
- let mut v = vec![1,2,3,4]; //創(chuàng)建了一個(gè)Vector
- print_vector(&mut v);
- println!(" the 1st element is {}",v[0]);
- }
- fn print_vector(v: &mut Vec<i32>) {
- v.push(3);
- ......
- }
總結(jié)一下:
張大胖繼續(xù)寫代碼,想繼續(xù)測(cè)試這個(gè)所謂“借用”:
- fn main() {
- let mut x = String::from("hello");
- let x1 = &x;
- let x2 = &mut x;
- println!("{}", x1);
- }
編譯還是出錯(cuò):‘x’已經(jīng)有一個(gè)不可變借用了,不能再以可變的方式來(lái)借用!
張大胖徹底懵逼了!想我叱咤編程界多年,先后學(xué)會(huì)了C,C++, Java, Ruby ,Python, 從來(lái)就沒見過(guò)這么復(fù)雜的語(yǔ)言,這么簡(jiǎn)單的程序,編譯都通不過(guò)。
Rust編譯器:道理很簡(jiǎn)單,x1是不可變引用,x2是可變引用,使用x1的"用戶"可不希望訪問(wèn)x1時(shí),數(shù)據(jù)已經(jīng)改變了。我告訴你一個(gè)簡(jiǎn)單的口訣,以后再遇到問(wèn)題就迎刃而解了:共享不可變, 可變不共享。
(用嚴(yán)格的描述來(lái)說(shuō)是這樣: 同一時(shí)刻,要么只有一個(gè)可變(&mut)借用,要么有多個(gè)不可變(&) 借用,不能同時(shí)存在可變和不可變借用。
(都對(duì)一個(gè)對(duì)象做讀操作,安全!)
(只有小張可以寫,因?yàn)樗强勺兊慕栌?
張大胖琢磨了一下,這口訣用人話來(lái)說(shuō)是這樣的: 當(dāng)大家都在讀一個(gè)東西的時(shí)候,是不能寫的。當(dāng)一個(gè)人在寫的時(shí)候,別人是不能讀的, 這不就是經(jīng)典的讀寫鎖問(wèn)題嗎?這Rust居然在編譯器級(jí)別做了這種限制 !
Rust編譯器:我之所以由這么嚴(yán)格的限制,就是為了內(nèi)存安全,我的這套體系是不需要GC的,只要你能按照我的規(guī)矩來(lái),內(nèi)存安全就能保證。
張大胖:你啊,是為了懶省事,把本來(lái)可以讓虛擬機(jī)干自動(dòng)做的事情,都交給程序員來(lái)做了,這是要把我們累死啊!
Rust編譯器:你到底做過(guò)系統(tǒng)級(jí)編程沒有?系統(tǒng)級(jí)編程要求:
1. 非???/p>
2. runtime 很小(虛擬機(jī)就是一個(gè)巨大無(wú)比的Runtime)
3. 能直接訪問(wèn)內(nèi)存,并且內(nèi)存安全。
C和C++基本滿足,但是內(nèi)存不安全, 像Java, Python,Ruby 除了內(nèi)存安全之外,別的都不滿足,只適合應(yīng)用層編程。
張大胖無(wú)語(yǔ)了,這家伙的目標(biāo)是要替換C/C++,自己也寫過(guò)不少C代碼,由于內(nèi)存問(wèn)題,不知道搞垮過(guò)多少個(gè)程序,懸空的指針就像幽靈一樣到處飄蕩,無(wú)蹤可循,然后在一個(gè)未知的地點(diǎn),未知的時(shí)刻突然爆裂。
這個(gè)Rust,每個(gè)對(duì)象都有唯一的“主人”,然后有對(duì)讀寫施加了這么嚴(yán)格的限制,如果程序員掌握了,確實(shí)比C語(yǔ)言安全, 我還是接著學(xué)吧!
【本文為51CTO專欄作者“劉欣”的原創(chuàng)稿件,轉(zhuǎn)載請(qǐng)通過(guò)作者微信公眾號(hào)coderising獲取授權(quán)】