当前位置:首页 » 《我的小黑屋》 » 正文

千万别学Rust!

18 人参与  2024年11月16日 14:42  分类 : 《我的小黑屋》  评论

点击全文阅读


张大胖被别人安利了一个新的语言:Rust,说是将来会替代C语言,就连Linux都要使用Rust了。

03eebc1e5e25e908eda0834f9cbec417.jpeg

作为编程语言的狂热爱好者,他自然要尝试一番。 

第一个程序自然是hello world,太简单了,都懒得去写,看看就行了:

fn main() {   println!("hello world");}

张大胖原来用过C语言, 当时觉得非常不爽的是它本身没有内置常用的数据结构,比如一个可以动态增长的数组,这Rust怎么样呢?

fn main() {    let v = Vec::new(); //创建了一个数组    v.push(4);  // 向数组添加一个元素}

张大胖写下let就意识到,这里是将值(数组)绑定到变量v , 应该是借鉴了Lisp的模式匹配,可以预见将来会遇到这样的代码: 

let (name,age) = ("Andy", 30);

还有就是这Rust具备自动类型推断能力,这点挺不错的。 

编译吧!咦,居然失败了,错误信息是:cannot borrow `v` as mutable, as it is not declared as mutable

Rust编译器:我们把对象分为可变的和不可变的,对于不可变的,一旦创建以后,就不能再改了。那就加个关键字mut,让它变成可变的就可以了:let mut v = Vec::new()

张大胖想起了《effective java》中的一条实践:把可变性限制到最小。他嘴里咕哝着:“嗯,Rust默认是不可变,这个思路也许是对的。”

所有权

他又探索着写下一些代码:

fn main() {    //用另外一种方式创建了一个可变Vector     let mut v = vec![1,2];       let v1 = v;    println!(" the 1st element is {}",v[0]);    }

编译,又失败了,WTF!到底是怎么回事?这么简单的程序也会出错?!

Rust编译器:谁让你手贱!加了一行代码:let v1 = v

张大胖:这有什么关系?在Java中,这就相当于对同一个对象,又添加了一个引用而已

Rust编译器:那是Java,在我Rust这里,你一定要放下Java的执念!要理解一下所有权的问题。

张大胖:什么所有权?

Rust编译器:对于任何给定的对象都只有一个绑定与之对应。你用let mut v = Vec::new()就意味着 v 和这个Vector对象绑定了!现在v拥有这个对象的所有权。这一行代码 let v1 = v ,让所有权发生转移了, 现在v1是新主人了。v就不能再访问这个Vector, 我把这种情况叫做“转移语义”。

31d9338422f4f249efbe3877288a09fa.png

码农翻身注:实际上, Rust也支持Copy语义,这里不在详述。

张大胖不满地说:这不是徒增烦恼吗?那我要是把v传递给另外一个函数呢?

fn main() {    let mut v = vec![1,2,3,4]; //创建了一个可变Vector    print_vector(v);    println!(" the 1st element is {}",v[0]);}fn print_vector(v: Vec<i32>){    for i in v {        println!("{}", i);    }}

编译还是出错!

Rust编译器:这和刚才是一个道理,v的所有权在传递给函数时,被拿走了,所以在main中不能再访问v了 ! 

借用

张大胖:太变态了,我就是想在调用print_vector以后想访问再访问变量v,该怎么办?

Rust编译器: 你可以把所有权暂时借用(&v)给print_vector,等函数返回就可以接着使用了

fn main() {    let mut v = vec![1,2,3,4]; //创建一个可变Vector    print_vector(&v);    println!(" the 1st element is {}",v[0]);    }fn print_vector(v: &Vec<i32>){  ......}

这个借用就相当于Java语言的引用了,张大胖想,print_vector函数已经“借到”所有权,应该可以为所欲为了吧,于是在函数内做了修改:

fn print_vector(v: &Vec<i32>) {    v.push(3);    .....}

再次编译,再次失败!张大胖感觉到要吐血了,这Rust实在太不讲道理了。 

Rust编译器:“你这个借用想要改变原来的对象,也得加上 &mut才行!”

fn main() {    let mut v = vec![1,2,3,4]; //创建了一个Vector    print_vector(&mut v);    println!(" the 1st element is {}",v[0]);    }fn print_vector(v: &mut Vec<i32>) {    v.push(3);    ......}

总结一下:

739b0fad856d7a803278a0242b9fdc71.png

张大胖继续写代码,想继续测试这个所谓“借用”:

fn main() {    let mut x = String::from("hello");    let x1 = &x;    let x2 = &mut x;        println!("{}", x1);    }

编译还是出错:‘x’已经有一个不可变借用了,不能再以可变的方式来借用!

张大胖彻底懵逼了!

想我叱咤编程界多年,先后学会了C,C++, Java, Ruby ,Python, 从来就没见过这么复杂的语言,这么简单的程序,编译都通不过。

Rust编译器:道理很简单,x1是不可变引用,x2是可变引用,使用x1的"用户"可不希望访问x1时,数据已经改变了。我告诉你一个简单的口诀,以后再遇到问题就迎刃而解了:共享不可变, 可变不共享。

(用严格的描述来说是这样: 同一时刻,要么只有一个可变(&mut)借用,要么有多个不可变(&) 借用,不能同时存在可变和不可变借用。 

)

cf1288096edfed92fa2cc8d0ab08e37b.png

(都对一个对象做读操作,安全!)

6b5fe6f9b157a0aef5f2052a42d1f2d9.png

(只有小张可以写,因为他是可变的借用)

张大胖琢磨了一下,这口诀用人话来说是这样的: 当大家都在读一个东西的时候,是不能写的。当一个人在写的时候,别人是不能读的, 这不就是经典的读写锁问题吗?这Rust居然在编译器级别做了这种限制 !

Rust编译器:我之所以由这么严格的限制,就是为了内存安全,我的这套体系是不需要GC的,只要你能按照我的规矩来,内存安全就能保证。

张大胖:你啊,是为了懒省事,把本来可以让虚拟机干自动做的事情,都交给程序员来做了,这是要把我们累死啊!

Rust编译器:你到底做过系统级编程没有?系统级编程要求:

1. 非常快

2. Runtime 很小(虚拟机就是一个巨大无比的Runtime)

3. 能直接访问内存,并且内存安全。 

C和C++基本满足,但是内存不安全, 像Java, Python,Ruby 除了内存安全之外,别的都不满足,只适合应用层编程。

张大胖无语了,这家伙的目标是要替换C/C++,自己也写过不少C代码,由于内存问题,不知道搞垮过多少个程序,悬空的指针就像幽灵一样到处飘荡,无踪可循,然后在一个未知的地点,未知的时刻突然爆裂。

这个Rust,每个对象都有唯一的“主人”,然后有对读写施加了这么严格的限制,如果程序员掌握了,确实比C语言安全, 我还是接着学吧!

全文完,觉得不错的话点个赞或者在看吧!

近期爆文

1970年以来技术的发展趋势,怪不得程序员35岁就被裁......

这个大学生写了个免费软件,全世界网民抢着给他送钱,每月10万美元

全世界流浪的程序员,用最原始的技术,每月赚17.6万美元!

开源软件的叛徒,加入了微软

Chrome背后最大的秘密:印度人拯救了Google!

这两个程序员要花100万,彻底重写世界上最复杂的软件

造福无数打工人,世界第7大网站,为什么过得如此卑微

被哈佛扫地出门,他发明了让无数程序员痛不欲生的编程语言,获得了计算机最高奖!

这两个大龄程序员,打算搞垮一个世界软件巨头!

世界上最大的盗版网站,遇到麻烦了!

这个女生写的软件,解决了无数程序员最头疼的问题!


点击全文阅读


本文链接:http://zhangshiyu.com/post/187162.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1