由于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; }
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()); }