Rust基础

指令

  • rustc -V: 版本
  • argo new demo01:创建项目:
  • cargo check:检查语法
  • cargo run:运行
  • cargo build :构建

变量

  • 可变性
  • 常量
  • 隐藏
const MAX_POINT:u32=10000;
fn main() {
    //变量定义
    let a=1;//默认类型可推导
    println!("a={}",a);
    // let b:u32=10;
    // b=30; //cannot assign twice to immutable variable:不能对不可变变量赋值两次

    //rust默认let定义变量,是不可变的,除非添加mut
    let mut b:u32=100;
    println!("b={}",b);
    b=30;
    println!("b={}",b);

    //隐藏性:后面变量会覆盖前面同名的变量,就叫隐藏性;之后代码使用的b就是浮点型的了
    let b:f32 =1.1;
    println!("b={}",b); //b=1.1

    //常量
    println!("MAX_POINT={}",MAX_POINT); //MAX_POINT=10000
}

数据类型

基础数据类型

  • bool
  • char 32位
  • 数字类型
  • 数组 [type;size]
  • 自适应类型
fn main() {
    //bool
    let a=true;
    let b:bool = false;
    println!("a={}",a);
    println!("a={},{}",a,b);//a=true,false   其实打印时候只和{}一一对应
    //char:rust中char是三十二位的,所以可以是汉字
    let c:char ='a';
    println!("c={}",c);//c=a
    //数字:i8 i16 i32 i64  ,u8 u16 u32 u64 ;前面是有符号的,后面是无符号的
    //f32  f64 浮点型

    let d:u8=10;
    println!("d={}",d);

    //自适应类型:isize(有符号) usize(无符号);会根据不同平台自适应,例如:16位平台,32位平台用usize这种就会不同
    println!("max={}",usize::max_value()); //max=18446744073709551615   usize的最大范围

    //数组:[type;size]     size也是数组类型的一部分

    let arr:[u32;5] =[1,2,3,4,5];//长度5的u32数组
    println!("arr[0]={}",arr[0]);//arr[0]=1
    // show(arr);//expected an array with a fixed size of 3 elements, found one with 5 elements
    //从上可知,size也是数组类型的一部分
}

fn show(arr:[u32;3]){
    for i in &arr{
        println!("{}",i);
    }
}

复合数据类型

  • 元组
  • 结构体
  • 枚举
fn main() {
    //元组
    let tup:(i32,f32,char) =(-3,3.68,'哈');
    println!("{}-{}-{}",tup.0,tup.1,tup.2); //-3-3.68-哈
    //结构体
    //枚举
}

函数


fn other_fun(a:i32,b:u32){
// fn other_fun(){ //error 这个时候没办法自动推导,会报错
    println!("a={},b={}",a,b);
}

fn other_fun1(a:i32,b:i32) -> i32 {
    //如果此处a,b类型不同则不能放一起相加
        return a+b;
}
fn other_fun2(a:i32,b:i32) -> i32 {
    //    let r=a+b;

    //注意:下面三种返回方式等效,后面两种都没有分号
    //    return r;
        // r
        a+b
}
fn main() {
    let a:i32 =-1;
    let b:u32 =20;
    other_fun(a,b);
    let c:i32=10;
    let r:i32 = other_fun1(a,c); //直接打印该行不可行,因为不知道类型,所以需要变量接收
    println!("r={}",r);//r=9
    let r1:i32=other_fun2(a,c);
    println!("r1={}",r1);


    //语句是执行一些操作,但是不返回值的指令
    // let y=1; //语句,不返回值


    //  表达式会计算一些值
    let y={
        let x=1;
        // x+1;  //加上分号就是语句啦,但是语句是不返回值的指令的;直接打印y,反而会报错
        x+1  //没加分号相当于计算一个值返回
    };
    println!("y={}",y); //y=2
}

控制流

fn main() {
    //if
    let y=1;
    if y==1 {
        println!("y={}",y);
    }
    //if-else
    if y==1 {
        println!("y={}",y);
    }else{
        println!("y={}",y);
    }
    //if-else if-else
    if y==1 {

    }else if y==2{

    }else{

    }

    //let中使用if
    let a=true;
    let x=if a{
        5
    }else{
        6  //注意:内部的返回必须在不同条件都一致,否则rust无法推导具体类型
    };
    println!("x={}",x);//x=5

    //循环十次跳出
    let mut counter=0;
    loop{
        println!("in loop");
        if counter==10 {
            break;
        }
        counter+=1;
    }
    let mut counter1=0;
   let res= loop{
        if counter1==5 {
            break counter1;
        }
        counter1+=1;
    };
    //这种就是接受loop的返回值的方式
    println!("res={}",res);//res=5


    //while循环
    let mut i=0;
    while i!=10{
        i+=1;
    };
    println!("i={}",i); //i=10

    //for循环
    let arr:[u32;5]=[1,2,3,4,5];
    for i in arr.iter(){
        println!("i={}",i);
    }
    //方式二:使用引用,和上面等效
    for i in &arr{
        println!("i={}",i);
    }
}

所有权

  • String的内存模型


    a.png
// 1. rust通过所有权机制来管理内存,编译器在编译期就会根据所有权规则对内存的使用进行检查
// 2. 堆和栈
//存储在栈上的需要大小固定;存储在堆上的可变;这是在编译期就确定的,所以可以通过这个方式判断具体变量是在哪里
// 3. 作用域:{}  作用域就是定以所在的花括号范围内,常规理解即可
// 4. String内存回收
// 5. 移动
// 6. clone
// 7. 栈上数据拷贝
// 8. 函数和作用域

fn main() {
    {
        //s1定以在堆上面的,string类型在编译期编译器是不知道它大小的,因为其可能还有追加
        let mut s1=String::from("hello");
        s1.push_str("a");
        println!("s1={}",s1); //s1=helloa
        //String类型离开作用域的时候会调用drop方法,类似于c++的析构函数
    }
    {
        let  s1=String::from("hello");
        let s2=s1;

        println!("s2={}",s2); //s1=hello
        // println!("s1={}",s1); //value borrowed here after move :被借用之后使用是会报错的
        //因为s1和s2实际上指向同一份内存地址,只是浅拷贝;但是在rust中离开作用域字符串会调用drop
        //此时会调用两次,明显是不合理的;所以rust语言做了处理,在s2=s1之后,s1就被干掉了等于;同理也不能使用了


        //clone
        let s3=s2.clone();//深拷贝,解决上面的问题
        println!("s3={}",s3); //s3=hello
    }
    {
        //栈上数据拷贝:copy trait
        //只要实现了copy的trait特性,则即使赋值之后也是可以继续使用的,而不会移除;后面再细研究
        let a=1;
        let b=a;//栈上面的数据实际上就是直接拷贝,没有指针
        println!("a={},b={}",a,b);//a=1,b=1

        //常用的具有copy  trait有:
        //所有的整型
        //浮点型
        //布尔值
        //字符类型
        //元组
    }
    let s=String::from("hello world");
    takes_ownership(s);
    //s传递进入,然后takes_ownership内部有{}会drop;rust会干掉当面作用域的s,所以下面的打印报错;但是例如整型就不会,因为是深拷贝
    //如果需要继续使用s,则可以在函数内部直接返回,然后这边接收即可

    // println!("{}",s); //value borrowed here after move

}

fn takes_ownership(s:String){
    println!("{}",s);
}

引用和借用

fn gives_ownership() ->String {
    let s=String::from("hello");
    s
}
fn takes_and_gives_back(s:String) -> String {
    s
}
fn main() {
    let s1=gives_ownership();
    println!("{}", s1);//此处可用,因为gives_ownership内部的s通过返回值把所有权转移给了s1
    let s2=String::from("hello");
    let s3=takes_and_gives_back(s2);
    // println!("{}",s2);//此处报错,因为s2所有权已经转交给s3了
    println!("s3={}",s3);

    let mut s4=String::from("hello");
    //引用 &:
    let a=calcute_length(&s4);
    println!("长度是={}",a); //长度是=5
    println!("还可以继续使用s4={}",s4);//重点

    //借用:&mut 
    modify_str(&mut s4);
    println!("s4={}",s4); //s4=helloa
    test();
    //此处就是悬垂引用:报错
    let r= test1();
}
//引用:创建一个指向值得引用,但是并不是拥有它,因为不拥有这个值;所以当引用离开其值指向得作用域后也不会被丢弃
fn  calcute_length(s:&String) -> usize {
    s.len()
}
//借用:引用只是指向不是拥有,所以需要操作得时候,需要使用借用
fn modify_str(s:&mut String){
    s.push_str("a");
}

fn test(){
    //如下代码是有错得:
    //因为,两个引用r1 r2,最后打印实际上按照常规理解是输出两个hello
    //但是实际上因为r3=&mut s1; 是借用,可能改变s1的内容
    //rust为了避免该种情况发生,会报错


    let mut s1=String::from("hello");
    let r1=&s1;
    let r2=&s1;
    println!("{},{}",r1,r2);  //此处使用是没有问题的
    let r3=&mut s1; 
    r3.push_str(",world");
    //也就是说,r3确实操作能修改s1,但是如果后面再使用了r1,r2;则rust会报错
    // println!("{},{}",r1,r2);  //immutable borrow later used here
}

fn test1()->&String{
    //悬垂引用:类似于野指针,因为s在当前{}之外就会回收了,&s只是引用,不是拥有,返回其实就是野指针了
    let s=String::from("hello");
    &s
}   

slice

//1. 字符串slice是String中一部分值得引用
//2. 字面值就是slice
//3. 其他类型slice

fn main() {
    let s=String::from("hello world");
    let h=&s[0..5];
    // let h=&s[0..=5];//等效于上面
    // let h=&s[..=5]; //不写表示从头
    // let h=&s[..5]; 
    println!("h={}",h);//h=hello
    //还可以
    // let h=&s[6..]; //6到结尾
    // let h=&s[..]; //直接等于s


    //字面值slice
    let s1="hh";//是不可变引用类型:&str

    //其他类型得slice
    let a=[1,2,3,4];
    let s2=&a[1..3];
    println!("s2[0]={}",s2[0]); //s2[0]=2
}

结构体

fn main(){
    //1. 定义结构体
    #[derive(Debug)]
    struct User {
        name: String,
        cunt: String,
        nonce: u64,
        active: bool,
    };
    //2.创建结构体实例
    let xiaoming =User{
        name: String::from("xiaoming"),
        cunt: String::from("80001000"),
        nonce: 1000,
        active: true,
    };
    
    println!("xiaoming={:?}", xiaoming); //xiaoming=User { name: "xiaoming", cunt: "80001000", nonce: 1000, active: true }

    //3. 修改结构体字段
    let mut xiaohuang =User{
        name: String::from("xiaohuang"),
        cunt: String::from("252352352"),
        nonce: 10020,
        active: true,
    };
    xiaohuang.nonce=20000;
    //4. 参数名字和字段名字
    let name = String::from("xiaoxiao");
    let cunt=String::from("80935235");
    let nonce=20000;
    let active=false;
    let u1=User{
        name
        cunt
        nonce
        active
    }
    //5. 从其它结构体创建实例
    let u2=User{
        name:String::from("u2"),//这样name就使用了自己定义得
        ...u1
    };
    let u3=User{
        ...u1
    };
    //下面是比较死板得方式,推荐上面得
    let u4=User{
        name:u1.name
    };
    //6. 元组结构体
    // (1) 字段没有名字
    // (2)圆括号
    struct Point(i32,i32);
    let a=Point(10,20);
    let b=Point(30,11);
    println!("a.x={},a.y={}",a.0,a.1);//此处注意

    //7. 没有任何字段得类单元结构体
    struct A{}
    //8. 打印结构体
    // #[derive(Debug)]
    //对应结构体上面加一个这个,代表自动推导,就可以直接打印结构体,而不是一个个属性得来了

    //注意此处是{:?}
    // println!("xiaoming={:?}", xiaoming); //xiaoming=User { name: "xiaoming", cunt: "80001000", nonce: 1000, active: true }
    // println!("xiaoming={:#?}", xiaoming);//这种方式会换行打印,更易于观看
}

方法

#[derive(Debug)]
struct Dog{
    name:String,
    weight:f32,
    height:f32,
}

impl Dog{
    fn get_name(&self) ->&str {
        // &(self.name[..])
        //下面方式也可以
        &self.name
    }
    fn get_weight(&self) ->f32{
        self.weight
    }
    // fn get_height(&self) ->f32{
    //     self.height
    // }
    fn show(){
        println!("jiao")
    }
}
impl Dog{
    //可以有多个实现,所以方法也可以分开写
    fn get_height(&self) ->f32{
        self.height
    }
}

fn main() {
    let d=Dog{
        name: String::from("wangcai"),
        height:3000.6,
        weight:20.1,
    };
    println!("dog={:#?}",d);
    /*
    dog=Dog {
    name: "wangcai",
    weight: 20.1,
    height: 3000.6,
}
    */
    println!("name={}",d.get_name()); //name=wangcai
    println!("weight={}",d.get_weight());//weight=20.1
    println!("height={}",d.get_height());//height=3000.6
    Dog::show(); //jiao   调用方法
}

枚举类型与匹配

//结构体在函数内部则最后需要分号,因为是语句,但是定义在外面得时候不需要

//1.类似于c语言得方式定义
enum IpAddKind{
    V4,
    V6,
}
//2.rust语言提倡得方式定义
enum IpAddr2{
    V4(String),
    V6(String),
}

//3. 可以是不同类型
enum IpAddr3{
    V4(u8,u8,u8,u8),  //元组
    V6(String),
}

//4. 经典用法
enum Message {
    Quit,
    Move{x:i32, y:i32},//结构体
    Write(String),
    Change(i32,i32,i32),
}
//等同于
/* struct QuitMessage;//类单元结构体
struct MoveMessage{
    x:i32,
    y:i32,
}
struct WriteMessage(String)
struct ChangeMessage(i32,i32,i32)*/

//5. 枚举类型得方法以及match
impl Message{
    //match 类似于c中得switch
    fn prin(&self){
        match *self{
            Message::Quit=>println!("Quit"),
            Message::Move{x,y}=> println!("Move x={},y={}",x,y),
            Message::Change(a,b,c)=> println!("Change a={},b={},c={}",a,b,c),
            _=> println!("default"),//_类似于default
            //结构体里面是字符串,结果发现传递进去是引用,所以不行会报错,一般用上面得_形式去打印
            // Message::Write(&s)=> println!("Write={}",s),
        }
    }
}
fn main() {
    struct IpAddr{
        kind: IpAddKind,
        address:String,
    };
    let i1=IpAddr{kind: IpAddKind::V4, address:String::from("127.0.0.1")};
    let i1=IpAddr2::V4(String::from("127.0.0.1"));
    let i1=IpAddr3::V4(127,0,0,1);
    let i2=IpAddr3::V6(String::from("127.0.0.1"));
    
    //枚举类型得方法以及match
    let quit=Message::Quit;
    quit.prin();
    let mo=Message::Move{x:127,y:0};
    mo.prin();
}

Option

//1. Option是标准库定义得一个枚举,形式:
// enum Option<T> {
//     Some(T),
//     None,
// }

//2.使用方式
fn main() {
    let a1=Some(1);
    let a2=Some(String::from("a string"));
    let a3:Option<i32> =None;

    let x:i32 =5;
    let y:Option<i32> =Some(5);
    let mut temp=0;
    //注意此处,如果直接x+y是不行得,因为i32和Option<i32>是两种类型,因为Option中可能存在none,所以需要匹配处理
    match y{
        Some(i) =>{temp=i;}
        None=>println!("do nothing")
    }
    let sum=x+temp;
    println!("sum={}",sum); //sum=10
    let result=plus_one(y);
    match result{
        Some(i)=>println!("result={}",i), //result=6
        None=>println!("nothing"),
    }
    //但是如果不想匹配none呢?可以使用下面的方式
    if let Some(value) =plus_one(y){
        println!("value={}",value); //value=6
    }else{
        //此处处理none得情况,但是实际上可以省略得
        println!("do nothing");
    }
}
fn plus_one(x:Option<i32>)->Option<i32>{
    match x{
        None =>None, //match必须把Option得所有类型都匹配完,否则编译报错
        Some(x) =>Some(x+1),
    }
}

Vector

//1. 创建空得vector: Vec<T>
//2. 创建包含初始值得vector
//3. 丢弃vector
//4. 读取元素
//5. 更新
//6. 遍历
//7. 使用枚举


fn main() {
    //1. 空Vector,但是如果空的,因为不可变性,所以其实后续操作无意义,一般都加上mut
    // let mut v:Vec<i32> = Vec::newnew();
    // v.push(1);
    //2
    let v=vec![1,2,3];//带有初始值
    //3
    {
        let v=vec![1,2,3];
        //花括号之外就会被丢弃
    }
    //4
    let one:&i32=&v[0];
    println!("one={}", *one); //one=1
    // println!("one={}", one);//同上,实际上只是自动划换,本质还是加上*

    //推荐
    match v.get(1){
        Some(v) => println!("v={}", v),//v=2
        _=> println!("do nothing"), //越界会到这里,不会报错,但是上面&v[index];如果越界则会报错
    }
    //5
    let mut v2:Vec<i32>=Vec::new();
    v2.push(1);//添加
    v2.push(11);
    //6
    //(1)不可变得遍历
    for i in &v2{
        println!("i={}", i);
    }
    //(2)可变得遍历
    for i in &mut v2{
        //遍历过程中修改原来得数据
        *i+=1;
        println!("i={}",i);
    }
    //7:可以把很多类型放在一个vec中,后续工作中可能会用到
    enum Context{
            Text(String),
            Float(f32),
    };
    let c= vec![
        Context::Text(String::from("string")),
        Context::Float(0.01),
    ];

    //8. 补充
    let mut v=vec![1,2,3,4,5];
    let first=&v[0];//此处是不可变引用
    v.push(6);//此处相当于可变引用
    // println!("first={}",first);//所以此处使用会直接报错
}

字符串

fn main() {
    //1. 创建一个空String
    let mut s0=String::new();//如果不加mut,因为不可变性,则无任何意义
    //2. 通过字面值创建一个String
    let s1=String::from("safsaf");
    let s1="safsaf".to_string();//等效于上面String::from
    println!("s1={}", s1);
    //2.1 使用String::from()
    //2.2 使用str方式
    //3. 更新String
    //3.1 push_str
    s0.push_str("sfa");
    println!("s0={}", s0);//s0=sfa
    //3.2 push:只能添加一个字符,用单引号
    s0.push('a');
    // s0.push_str("sfa");
    //3.3 使用+合并字符串
    let s1="hello".to_string();
    let s2=String::from(" ,world");
    // let s3=s1+s2;//这样会报错
    let s3=s1+&s2;
    println!("s3={}", s3); //s3=hello ,world
    // println!("s1={}", s1); //报错,s1+&s2相当于把s1所有权给了s3,所以之后使用s1,报错;但是s2还可以使用,因为添加的是引用
    //3.4 使用format
    let s431=String::from("tic");
    let s432=String::from("tac");
    let s433=String::from("toe");
    let s434=format!("{}-{}-{}",s431,s432,s433);
    println!("s434={}", s434); //s434=tic-tac-toe;注意:之后s431,s432,s433还都可以正常使用
    //4. String索引
    let s4=String::from("hello");
    // let s41=s4[0];  //报错,String类型不能被索引
    // 因为rust中字符是UTF-8编码,所以可能出现汉字,肉眼的0其实不是0,所以rust就避免了这种情况出现,直接报错

    //5. str索引:这种方式可以,slice方式
    let hello="你好1";//slice字符串
    let h5=&hello[0..3];//但是如果是到2,则报错,因为2不是边界,例如汉字三个字符
    println!("h5={}",h5); //h5=你
    //6. 遍历
    //6.1 chars
    for c in hello.chars() {
        println!("c={}",c); //分别打印 c=你   c=好; c=1  会自动转字符打印,根本中英文
    }
    println!("--------------");

    //6.2 bytes
    for c in hello.bytes() {
        println!("c={}",c); 
    }
    //输出如下
    // c=228
    // c=189
    // c=160
    // c=229
    // c=165
    // c=189
    // c=49
}

HashMap类型

use std::collections::HashMap;//导入库,内置的
fn main() {
    //1. 创建HashMap<K,V>,
    let mut scores:HashMap<String,i32> = HashMap::new();
    scores.insert(String::from("Blue"),10);
    scores.insert(String::from("Red"),20);
    //2. 创建HashMap
    let keys =vec![String::from("Blue"),String::from("Red")];
    let values =vec![10,20];
    //组合成hashmap
    let scores:HashMap<_,_> =keys.iter().zip(values.iter()).collect();
    //3. 读取
    let k=String::from("Blue");
   if let Some(v)=scores.get(&k){
       //返回的是option,所以这样打印,不能直接打印会报错
       //也可以用Match方式
       println!("v={}",v); //v=10
   }
    //4. 遍历
    for(key,value) in &scores{
        //但是注意:遍历是无序的
        println!("{},{}",key,value); //Blue,10 以及Red,20
    }
    //5. 更新
    //插入
    let mut ss=HashMap::new();
    ss.insert(String::from("Yellow"),30);
    ss.insert(String::from("Red"),22);
    println!("{:?}",ss); //{"Yellow": 30, "Red": 22}
    //键不存在才插入
    let mut ss1=HashMap::new();
    ss1.insert(String::from("Yellow"),30);
    ss1.insert(String::from("Red"),22);
    ss1.entry(String::from("Yellow")).or_insert(3);//不存在该键才插入3
    println!("{:?}",ss1); //{"Yellow": 30, "Red": 22}
    //根据旧值更新一个值
    let text="hello world wonderful world";
    let mut map=HashMap::new();
    //split_whitespace是按照空格分割
    for word in text.split_whitespace(){
        let count=map.entry(word).or_insert(0);
        *count+=1;
    }
    //统计单词出现次数
    println!("map={:?}",map);  //map={"hello": 1, "wonderful": 1, "world": 2}
}

模块

一旦涉及模块,则必须通过cargo run 运行项目

b.png
  • 案例一:同一个文件中的模块
mod factory{
    pub mod produce_r1{
        pub fn produce_r11(){
            println!("公有的才能在外部被调用");
        }
    }
    mod produce_r2{
         fn produce_r22(){
            println!("rust默认模块内部都是私有的");
        }
    }
}
fn main() {
    factory::produce_r1::produce_r11();//公有的才能在外部被调用
}

引用自定义模块

自定义模块一般也在项目内部的创建
进入项目文件夹,执行下面指令

`cargo new --lib mylib`

factory.rs本身是没有的,后期创建的,默认只有lib.rs
image.png
//lib.rs

//模块声明为pub-相当于声明了factory.rs为模块且是pub,这是必须的,否则外部根本引用不了
pub mod factory;

//以下是自动生成的
#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
  • factory.rs
pub mod produce_r1{
    pub fn produce_r11(){
        println!("公有的才能在外部被调用");
    }
}
mod produce_r2{
     fn produce_r22(){
        println!("rust默认模块内部都是私有的");
    }
}
  • 项目的Cargo.toml
[package]
name = "demo01"
version = "0.1.0"
authors = ["zengqiang"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
mylib = {path='./mylib'} # 这就是添加自定义lib引用,此处是相对路径,可变化的
  • 示例
//外部导入lib
use mylib::factory::produce_r1;
// use mylib::factory::*;//导入该文件所有,而不是具体mod
use mylib::factory::produce_r1 as A;//别名
//其实还可以到下一级,但是不方便导入的服用,类比import

//方便观看,直接在该文件定义mod,说明在mod中使用结构体的问题
mod modA{
    #[derive(Debug)]
    pub struct A {
        pub num:i32,
        name: String,
    }
    impl A {
        pub fn new_a()->A{
            A{
                num:1,
                name: String::from("a"),
            }
        }
        pub fn print_a(&self){
            println!("num={},name={}",self.num,self.name);
        }
    }

    pub mod modB{
        pub fn print_b(){
            println!("B");
        }
        //C模块想用B模块的函数使用super
        pub  mod modC{
            pub fn print_c(){
                super::print_b();
                println!("C");
            }
        }
    }
    
}

use modA::A as A1;
fn main() {
    //绝对路径调用
    mylib::factory::produce_r1::produce_r11();//公有的才能在外部被调用
    //使用use 等效于上面
    produce_r1::produce_r11();//公有的才能在外部被调用
    A::produce_r11(); //公有的才能在外部被调用


    //结构体
    let a=modA::A::new_a();
    a.print_a();//num=1,name=a

    //重要
    modA::modB::modC::print_c(); //B   C
}

使用外部的库

  • 项目的Cargo.toml下添加依赖
[package]
name = "demo01"
version = "0.1.0"
authors = ["zengqiang"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rust-crypto="0.2" # 此处就是
  • 更改为国内镜像,加速下载(可省略)
1. 项目根目录下面创建`.cargo`文件夹
2. 文件夹下面创建config文件(无后缀)
  • 执行cargo build或者直接cargo run 都会自动下载包
  • 示例
extern crate crypto;//使用外部的库,不能省略
use crypto::digest::Digest;
use crypto::sha3::Sha3;
fn main() {
    //使用外部的库:生成hello world的hash值
    let mut hasher=Sha3::sha3_256();
    hasher.input_str("hello world");
    let result=hasher.result_str();
    println!("hash={}",result);//hash=644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938
}

错误处理(不全面)

use std::io;
use std::io::Read;
use std::fs::File;
fn main() {
   let r= read_username_from_file();
    // 此处r其实是Result:内置的枚举类型,有Ok和Err两个
   match r{
       Ok(s) => println!("s={}",s),
       Err(e) => println!("e={:?}",e), //e=Os { code: 2, kind: NotFound, message: "No such file or directory" }
   }
}

//基础方式:最麻烦
// fn read_username_from_file()-> Result<String, io::Error> {
//     let f=File::open("hello.txt");
//     let mut f=match f{
//         Ok(file) => file,
//         Err(e) =>return Err(e),
//     };
//     let mut s=String::new();
//     match f.read_to_string(&mut s) {
//         Ok(_) =>Ok(s),
//         Err(e)=>Err(e),
//     }
// }

//简写方式
// fn read_username_from_file()-> Result<String, io::Error> {
//     let mut f=File::open("hello.txt")?; //?代表有错误,直接走到io::Error中,否则继续往下走
  
//     let mut s=String::new();
//     f.read_to_string(&mut s)?;
//     Ok(s)
// }

//更简洁方式
fn read_username_from_file()-> Result<String, io::Error> {
    let mut s=String::new();
    File::open("hello.txt")?.read_to_string(&mut s)?;
    Ok(s)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容