为啥rust禁播_Rust 单链表的实现

0. 比较Windows和Ubuntu下开发Rust的区别

## Rust环境安装

> Widnows下,在 按照官方网站安装rust 后; 安装时要选windows下的工具链; 需要c++的tool-chains来编译 rust程序, 所以要安装VC++2010以上的开发环境,。

> Ubuntu下,在 按照官方网站安装rust 后(curl https://sh.rustup.rs -sSf | sh); 安装时应该安装linux下的工具链;需要linux c++的tool-chains秋编译程序,所以先使用sudo apt-get update更新系统组件,再使用sudo apt install build-essential ,在terminal中运行gcc --version正常运行就可以。

### valgrind 来检查内存泄露

> windows下不可用

> linux,mac下可用

### 编辑

都可以用VScode 和Clion来编写和运行Rust程序,Clion比vscode好用很多,有各种智能提示。

### 调试

> windows下只能使用vscode来编译rust 程序,rust工具链必须是windows-msvc,例如nightly-x86_64-pc-windows-msvc或者 stable-x86_64-pc-windows-msvc,还要安装Rust和C/C++插件,每次编译新项目时,需要重新修改lanuch.json的 type:cppvsdbg和 program:输出EXE的路径。使用vscode 调试,像段公子的六脉神剑一样,有时可以用,有时不可用,挺烦的。

>在Ubuntu下使用 Clion来编写和Debug Rust程序,当然也需要安装Rust插件;写完程序,然后再使用valgrind 来检测有没有内存泄露。Clion默认要使用gnu-toolchains, 如果安装 好了,直接就可以编译运行,不需要配置,很方便。 rust default 我默认使用nightly-x86_64-unknown-linux-gnu,有很多新特性。

以下代码都是在Ubuntu下编写和调试的。

1. 新建项目

> 使用cargo new  r1来创建一个可执行Rust项目,

crate-type:

--bin 默认选项; 上方命令完整形式为: cargo new r1 --bin ,输出 r1 on Linux and macos, r1.exe on windows。

--lib Normal Rustlibrary   输出 *.so files on linux, *.dylib files on osx, and *.dll files on windows.

--rlib A dynamic Rust library   输出 *.so files on linux, *.dylib files on osx, and *.dll files on windows.

--dylib A "Rust library" file;  输出 *.so files on linux, *.dylib files on osx, and *.dll files on windows.

--cdylib  A dynamic system library; 输出*.so files on Linux, *.dylib files on macOS, and *.dll files on Windows

--staticlib  A static system library; 输出 *.a archive on linux and osx and a *.lib file on windows.

--proc-macro Proc-macro library

2.  在main.rs同级目录下新建一个link.rs

use std::ptr::{NonNull, null};

use std::marker::PhantomData;

use std::boxed;

use std::borrow::BorrowMut;

use std::fmt::{Formatter, Error, Debug};

use core::fmt;

use std::iter::Cloned;

pub struct LinkedInnerNode {

value: T,

next: Option>>,

}

pub struct LinkedNode {

len: usize,

root: Option>>,

last: Option>>,

marker: PhantomData>>,

}

impl LinkedInnerNode{

pub fn getValue(&self)->&T{

&self.value

}

fn new(item:T)->Self{

LinkedInnerNode{value:item,next:None}

}

}

impl fmt::Debug for LinkedNode {

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

unsafe {

let mut last_node = &self.root;

let mut fun = || {

while *last_node != None {

println!("->{:?}", &(*last_node.unwrap().as_ptr()).value);

last_node = &(*last_node.unwrap().as_ptr()).next;

}

};

fun();

}

write!(f, "({})", "end;")

}

}

impl LinkedNode {

pub fn new(item:T) ->Self{

let init_node = Some(Box::into_raw_non_null(box LinkedInnerNode::new(item)));

LinkedNode{len:1,root: init_node,last:init_node, marker: PhantomData,}

}

#[inline]

pub fn size(&mut self)->usize{

self.len

}

pub fn push(&mut self,item:T)->&mut Self {

self.push_back(box LinkedInnerNode::new(item));

self

}

fn push_back(&mut self, item: Box>) ->&mut Self{

let mut last_node=&self.root;

let mut fun=|| {

while *last_node != None {

unsafe

{

if (*last_node.unwrap().as_ptr()).next == None {

(*last_node.unwrap().as_ptr()).next = Some(Box::into_raw_non_null(item));

break;

}

last_node = &(*last_node.unwrap().as_ptr()).next;

}

}

};

fun();

self.len +=1;

self

}

}

3. 修改 main.rs

#![feature(box_into_raw_non_null)]

#![feature(box_syntax)]

use std::ops;

use std::mem::drop;

use std::marker::PhantomData;

use crate::link::LinkedNode;

use std::ptr::NonNull;

mod link;

pub fn main() {

let mut node=LinkedNode::new(10);

let vc:Vec=vec![1,2,3,5];

println!("{:?}",&vc);

println!("{:?}",node.size());

println!("{:?}",node.size());

node.push(11).push(12).push(13);

println!("{:?}",node);

}

4.  编译并运行

[1, 2, 3, 5]

1

1

->10

->11

->12

->13

(end;)

看起来运行良好。

5.  使用 valgrind ./r1

==9771== Memcheck, a memory error detector

==9771== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.

==9771== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info

==9771== Command: ./r1

==9771==

[1, 2, 3, 5]

1

1

->10

->11

->12

->13

(end;)

==9771==

==9771== HEAP SUMMARY:

==9771== in use at exit: 64 bytes in 4 blocks

==9771== total heap usage: 24 allocs, 20 frees, 3,489 bytes allocated

==9771==

==9771== LEAK SUMMARY:

==9771== definitely lost: 16 bytes in 1 blocks

==9771== indirectly lost: 48 bytes in 3 blocks

==9771== possibly lost: 0 bytes in 0 blocks

==9771== still reachable: 0 bytes in 0 blocks

==9771== suppressed: 0 bytes in 0 blocks

==9771== Rerun with --leak-check=full to see details of leaked memory

==9771==

==9771== For lists of detected and suppressed errors, rerun with: -s

==9771== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

发现有四个块并没有释放; 因为在unsafe块中使用 Box::into_raw_non_null来关联数据,实现上它里面有mem::forget标志离开该lifetime不释放空间。

5. 为了保证空间及时释放,可以实现drop特性,之前需要添加一个方法弹出第一个结点

fn pop_front_node(&mut self)-> Option>> {

let mut last_node = self.root;

if last_node == None{

return None;

}

let mut fun = || {

unsafe {

let node = Box::from_raw(last_node.unwrap().as_ptr());

self.root = node.next;

Some(node)

}

};

fun()

}

首先将root赋予last_node,那么last_node只能在该方法有效;一旦退出,last_node将会被释放。

6. 实现drop特性

impl Drop for LinkedNode {

fn drop(&mut self) {

struct DropGuard(&'a mut LinkedNode);

impl Drop for DropGuard {

fn drop(&mut self) {

while let Some(_) = self.0.pop_front_node() {}

}

}

while let Some(node) = self.pop_front_node() {

let guard = DropGuard(self);

drop(node);

mem::forget(guard);

}

}

}

有一个DropGuard是为了避免程序因为Panic退出而没有执行到Drop,继续执行执行清理工作,避免内存泄露。

7. 使用valgrind再检测一下

==10651== Memcheck, a memory error detector

==10651== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.

==10651== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info

==10651== Command: ./r1

==10651==

[1, 2, 3, 5]

1

1

->10

->11

->12

->13

(end;)

==10651==

==10651== HEAP SUMMARY:

==10651== in use at exit: 0 bytes in 0 blocks

==10651== total heap usage: 24 allocs, 24 frees, 3,489 bytes allocated

==10651==

==10651== All heap blocks were freed -- no leaks are possible

==10651==

==10651== For lists of detected and suppressed errors, rerun with: -s

==10651== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

没有泄露,很好;

参考了内库的linked_list.rs  on ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/liballoc/collections

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值