看rust的教程,基本的地方感觉都看懂了,但是真正写出来代码无数编译错误,所以打算先用leetcode来练习一下。目前已经做了几十道题了,写了上千行代码,感觉有点入门了,从模仿C++风格慢慢地转变成有点像rust风格了。
以第一题two sum为例,用hashmap,可以实现成这样:
impl
对于Some(&index),如果少写了&,就会出现编译错误。当然将该行改成这样也可以:
Some(index) => { return vec![*index, i as i32] }
如果前面不用&,后面就要加*。关于&和*的编译错误是刚开始学rust的人非常头痛的事情,因为有时候需要用&&,这个要慢慢理解。
rust的数据类型有很多它自己的语法糖,不少地方写起来会比其它语言看起来更简洁。比如说下面一句(m的类型是HashMap):
m
如果用c++写起来就是:
auto
这种用法在leetcode的题目里派得上用场的地方还挺多的,实际项目中很常见。对比之下,明显rust的写法要简洁得多。当然不是说rust就比c++简洁,比c++啰嗦的地方也很多。我举这个例子就是说每种语言都有它自己的语法糖,熟练了才能发挥这种语言的效能和威力,也才能发现这种语言的乐趣。
再看第二题add two numbers吧,第二题是个链表题。rust的链表对新手来说是很容易劝退的,leetcode上面的很多链表题,用rust来实现都是很蹩脚的,有些不用unsafe甚至无法实现。
其原因之一,链表刚好是rust不擅长的,就连rust目前标准库中的链表,功能也很弱,因为链表的特性和rust引以为傲的所有权机制刚好是相矛盾的;其原因之二,leetcode上面的链表类型都是:
Option<Box<ListNode>>
这种定义其实很操蛋的,大部分链表题的常规解法都是需要一个以上的指针指向相同或者不同的节点才能实现的,而leetcode的声明方法根本无法做到(rust不允许),如果声明成这样:
Option<Rc<RefCell<ListNode>>>
实现功能上就会稍微容易一点,但是leetcode的声明方式貌似都是第一种。所以说leetcode的链表题用rust不好做,leetcode本身也是有一半责任的。
就因为leetcode对于链表的声明方式,第二题就不太好做,因为结果是要把链表颠倒过来,需要用一个header和tail两个指针记录链表的头和尾,用Option<Box<ListNode>>不好实现。当然可以用递归的方法来做,因为递归做这种链表反序是很直观的,可以节省一个变量。不过我没用递归,我是用循环来做的。leetcode的第206题刚好是反转链表的简单题目,实现方法是类似的,206题实现如下:
impl
其实就是用Option类型的take(),简化了代码。第二题的完整代码我不贴了,都上传在了leetcode上,包括以后做的都会上传上去。代码在:
franktea/leetcode-rustgithub.com我打算用一年的时间,体验rust写一万行代码以上,然后再来决定要不要使用它。