项目作者: veaba

项目描述 :
learn rust, 40+ demos
高级语言: Rust
项目地址: git://github.com/veaba/learn-rust.git
创建时间: 2019-03-08T07:13:44Z
项目社区:https://github.com/veaba/learn-rust

开源协议:

下载


learn-rust

Book

错误

  • ^^^ std::result::Result<_, _> cannot be formatted with the default formatter
  • //#[derive(Debug)]的//去掉时能自动为Student实现std::fmt::Debug特性。
  • only valid in field-less enums
  • Employee cannot be formatted with the default formatter
  • not found in this scope
  1. pub fn arg_result(arg: String) -> tuple {
  2. | ^^^^^ not found in this scope
  3. error: aborting due to previous error
  1. // use
  2. let ab = utils::arg_result(arg);
  3. println!("arg result==?,{}", ab);
  4. println!("{:?}", arg);
  5. // var utils.rs
  6. pub fn arg_result(arg: String) -> tuple {
  7. // return ("a", "2");
  8. ("a","b")
  9. }
  • Use of moved value

    • 分析文章
      编译器说,我们新加入的行里用了“移动了的值”。

      啥叫“移动了的值”呢?

      说白了就是用过了的值,foo已经给第一个fn_a()用过了,到了第二个fn_a()的时候就是moved value了。然后就不让用了。

      至于为什么要制定这样的规则,解释

      现在我们开始动手来解决这个问题。

  • returns a value referencing data owned by the current function
    查看例子lifecycle/lifecycle.rs

  • cannot return value referencing local variable "temp_arg"
    查看例子lifecycle/lifecycle.rs

explicit lifetime required in the type of

入门知识点

  • rust 是静态类型,必须知道类型,且不能随更改类型

  • 变量隐藏和复写

    1. fn main(){
    2. let x =5;
    3. let x=x+1;
    4. let x =x*2;
    5. }
  • 倒数第二及以前的段落必须结尾加分号

  • 函数内部 最后一行如果不用return 的方式返回,就不能给该行使用分号

    • 表达式返回值
      ```rust
      fn main(){
      let x =five();
      println!(“{}”,x);
      }

// 如果函数最后一行不带return且不带分号,则认为是一个return,可省去关键字return
fn five()->i32{
5
}

  1. ## 疑问
  2. ### 1. 如何if == string?
  3. ### 2. while循环和for循环的区别:
  4. > 如果数组的索引长度在运行时增加,那么while循环显示错误,但在for循环的情况下不会发生这种情况。 因此,可以说for循环增加了代码的安全性并消除了错误的可能性。
  5. ### 3. 为什么要加!
  6. ### 4. 使用前,需要将变量声明,不存在js类似的变量提升
  7. ### 5. i32表示多少
  8. ### 6. 不能打印长元组?? 报错,WHY?
  9. ```rust
  10. fn main(){
  11. let too_long_tuple=(1,65,56,6,565,65,95,5,655,656,64,65,5,61,6,5656);
  12. println!("too long tuple:{:?}",too_long_tuple);
  13. }

7. rust 如何执行一段函数返回的代码,即函数返回值

  1. /*
  2. * @pair 入参一个,内含两个元素,数据类型为(i32,bool)元组
  3. * @return 返回值为 数据类型为,也是个元组 (bool,i32)
  4. */
  5. fn reverse(pair:(i32,bool))->(bool,i32){
  6. let (integer,boolean)=pair;
  7. (boolean,integer)
  8. }
  9. fn main(){
  10. let pair = (11,true);
  11. println!("{:?}",reverse(pair));
  12. }

8. rust 如何计算一个函数加值的运算,涉及到 :入参、返回值,类型

  1. fn main(){
  2. println!("{}",fool(999));
  3. }
  4. fn fool(num:i32)->(i32){
  5. return num+999; // 或者num+999,不需要return
  6. }

9. 为什么要加一个&?

答案:表示引用

  1. use std::mem;
  2. fn analyze_slice(slice:&[i32]){
  3. println!("第一个元素:{}",slice[0]);
  4. println!("数组的长度:{}",slice.len());
  5. }
  6. fn main(){
  7. let xs:[i32;5]=[9898,9856,685659,66,9];
  8. analyze_slice(&xs)//为什么要加一个&呢?
  9. }

10. match在函数中的作用

  1. - match 由分支(arms)构成,一个分支包含一个模式(pattern)
  2. - matchcmp方法会返回`Ordering:Greater`,`Ordering:Less`,`Ordering:Equal`
  1. fn inspect(event:WebEvent){
  2. // match干嘛的?
  3. match event {
  4. WebEvent::PageLoad=>println!("page load"),
  5. WebEvent::PageUnload=>println!("page unload"),
  6. WebEvent::Keypress(c)=>println!("pressed '{}'.",c),
  7. WebEvent::Paste(s)=>println!("pasted\"{}\".",s),
  8. WebEvent::Click {x,y}=>println!("click at x={},y={}",x,y)
  9. }
  10. }

11. 怎么打印枚举

  1. enum Point{
  2. x = 111
  3. }
  4. println!("{}");

12. return 部分返回的尖括号?

13. Ok(())是什么意义?

  1. - Result 风格,大写Ok,因为它是一个枚举enum
  2. - future中,使用小写ok方法【首选】

14. 函数括号加问号?

15. 怎么查看type 类型?

16. String 转为真正的数字类型

  1. let num:u32=guess.trim().parse().expect('xxx')

17. 如何取到键盘输入的值

io::stdin().read_line(&mut xx).expect(“错误~~”) ,存到一个变量

18. TODO 如何迭代/循环元组?

  1. fn main(){
  2. let long_tuple =(
  3. 1u8,2u16,3u32,4u64,
  4. -1i8,-2i16,-3i32,-4i64,
  5. 0.1f32,0.2f64,'a',true);
  6. }

19.TODO,比如test()? 这个后面的问号是干嘛的?

20. 问号是干嘛的?fs::write(“foo.txt”,”哈哈哈”)?;

21. 数字转字符串

22. 函数后面有个函数是干嘛?

  • 由于Rust中没有Exception异常处理的语法,
  • Rust只有panic报错, 并且panic不允许被保护, 因为没有提供 try 这种语法.
  • Rust的异常处理是通过 Result 的 Ok 和 Err 成员来传递和包裹错误信息.
  • 然而错误信息的处理一般都是要通过match来对类型进行比较, 所以很多时候
  • 代码比较冗余, 通过?符号来简化Ok和Err的判断.
  1. use actix_web::{web, App, HttpResponse, HttpServer};
  2. #[actix_rt::main]
  3. async fn main() -> std::io::Result<()> {
  4. HttpServer::new(|| {
  5. App::new().route("/", web::get().to(|| HttpResponse::Ok()))
  6. })
  7. .bind("127.0.0.1:8088")? //What is that ?
  8. .run()
  9. .await
  10. }

23. 为什么这里会变更掉变量值的类型

use of moved value

可以:utils::arg_result(arg.clone())解决问题

24. rust 的impl

  • impl 作为关键字定义参数类型
  • impl 关键字定义指定struct的实现代码,然后在这代码块中定义与struct相关的方法

25. rust 中的方法和函数

方法与函数非常相似

  • 方法:必须有与之关联的Struct,且第一个参数是self
    ```rust
    struct Style {
    width: u32,
    height: u32,
    }

impl Style {
fn area(&self) -> u32 {
self.width * self.height
}
}

fn main() {
let rect = Style {
width: 30,
height: 90,
};
println!(“{:?}”, rect.area())
}

  1. ### 26 文件调用别的文件的函数方法
  2. ```rust
  3. // a.rs
  4. use crate::shared::QRErrorCorrectLevel::H;
  5. // b.rs
  6. pub struct Code {
  7. width: i32,
  8. height: i32,
  9. type_number: i32,
  10. color_dark: String,
  11. color_light: String,
  12. correct_level: H,
  13. }
  14. // main.rs
  15. mod shared;

27. rust 如何实现类似 js 中的对象

28. rust &b”” ??

  1. use bytes::{Bytes}
  2. fn main(){
  3. let b = Bytes::new();
  4. println("{:?}",&b[..])
  5. }

看起来 bytes,声明是 b””, 需要 &x[..] 展开,然后是是一个数组

29. 引用 Reference

两种引用类型:

  • 共享指针:&
  • 可变指针:&mut

规则:

  • 引用的生命周期不能超过被引用内容
  • 可变引用不能存在别名

30. 借用 Borrow

31. Rust 生命周期

Rust 会通过分析引用对象的声明周期来防止引用一个不可用的对象。

生命周期的主要目标是为了防止悬空指针

  1. {
  2. let r;
  3. {
  4. let x =5;
  5. r = &x; // 被销毁了
  6. }
  7. println!("r :{}",r)
  8. }

外部作用域声明了变量r,内部作用域声明了变量x,在内部产生设置了rx的引用,当内部区域终止时,尝试打印r,上述代码无法通过编译。

查看例子lifecycle/lifecycle.rs

32. Vec

33. rust 函数如何返回一个不定长的数组?

  1. // error
  2. pub fn arg_array(arg:String) -> &mut [T] {
  3. ["a"]
  4. }
  5. // 其中一种方法
  6. pub fn arg_array(arg: String) -> Vec<&'static str> {
  7. println!("入参=>{}", arg);
  8. let array = ["das", "das","dsad"];
  9. println!("len =>{}",array.len());
  10. for i in 0..array.len(){
  11. vec.push(array[i])
  12. }
  13. return vec;
  14. }

34. rust 结构体里有结构如何打印?

  1. struct MainModule {
  2. user: String,
  3. // TODO auto 1 2 3 4 5 6
  4. worker_processes: u32,
  5. event: EventModule,
  6. // error_log: String,
  7. // pid: String,
  8. // worker_rlimit_nofile: u32,
  9. // http: HttpModule,
  10. }
  11. struct EventModule {
  12. worker_connections: u32,
  13. }
  14. fn main(){
  15. let config = MainModule {
  16. user: String::from("www www"),
  17. worker_processes: 2
  18. };
  19. println!("==>{:#?}", config.event) // why can;t print this?
  20. }

35. 类似这种结构,怎么打印Object 返回?

  1. fn main() {
  2. let object = json_to_struct();
  3. println!("{:#?}", object) // TestStruct` cannot be formatted using `{:?}`
  4. }
  5. fn json_to_struct() -> Result<()> {
  6. let json = r#"
  7. {
  8. "name":"asjdsak",
  9. "age":30,
  10. "type":true
  11. }
  12. "#;
  13. let v: Value = serde_json::from_str(json)?;
  14. println!("==>{:?}", v);
  15. Ok(())
  16. // TODO 如何返回v
  17. }

改动如下:

  1. use serde_json::{Result,Value};
  2. fn main() {
  3. let object = json_to_struct();
  4. println!("{:#?}", object) // TestStruct` cannot be formatted using `{:?}`
  5. }
  6. fn json_to_struct() -> Result<Value> {
  7. let json = r#"
  8. {
  9. "name":"asjdsak",
  10. "age":30,
  11. "type":true
  12. }
  13. "#;
  14. let v: Value = serde_json::from_str(json)?;
  15. println!("==>{:?}", v);
  16. Ok(v)
  17. }

二次改动

  1. use serde_json::{Result,Value};
  2. fn main() {
  3. let object = json_to_struct().unwrap();
  4. println!("{:#?}", object); // TestStruct` cannot be formatted using `{:?}`
  5. // println!("{:#?}", object) // TestStruct` cannot be formatted using `{:?}`
  6. // println!("name==>{:#?}", object.name);
  7. println!("=dsadd=>{}", object["name"]);
  8. }
  9. fn json_to_struct() ->Result<Value> {
  10. let json = r#"
  11. {
  12. "name":"asjdsak",
  13. "age":30,
  14. "type":true
  15. }
  16. "#;
  17. let v: Value = serde_json::from_str(json)?;
  18. println!("name===>{}",v["name"]);
  19. println!("==>{:?}", v);
  20. Ok(v)
  21. }

35. json字符串转struct

  1. extern crate rustc_serialize;
  2. use rustc_serialize::json;
  3. #[derive(RustcDecodable, RustcEncodable)]
  4. #[derive(Debug)]
  5. struct Profile {
  6. name: String,
  7. age: u8,
  8. phones: Vec<String>,
  9. }
  10. fn main() {
  11. let json_str = r#"
  12. {
  13. "name":"veaba",
  14. "age":26,
  15. "phones":[
  16. "110",
  17. "120",
  18. "119"
  19. ]
  20. }
  21. "#;
  22. let profile: Profile = json::decode(&json_str).unwrap();
  23. println!("json to struct==>{:#?}", profile);
  24. }

36. struct转json字符串

  1. extern crate rustc_serialize;
  2. use rustc_serialize::json;
  3. #[derive(RustcDecodable, RustcEncodable)]
  4. #[derive(Debug)]
  5. struct Profile {
  6. name: String,
  7. age: u8,
  8. phones: Vec<String>,
  9. }
  10. fn main() {
  11. let profile = Profile {
  12. name: "Jobs".to_string(),
  13. age: 99,
  14. // phones: vec!["110", "120", "199", "144"],
  15. phones: vec!["110".to_string(), "120".to_string(), "199".to_string(), "144".to_string()],
  16. };
  17. let encode = json::encode(&profile).unwrap();
  18. println!("struct to json==>{}", encode);
  19. }

37. struct 打印

38. struct 嵌套struct 如何转为json?

  1. extern crate rustc_serialize;
  2. use rustc_serialize::json;
  3. // Struct Parent
  4. #[derive(RustcDecodable, RustcEncodable)]
  5. #[derive(Debug)]
  6. struct Parent {
  7. name: String,
  8. age: u8,
  9. children: Children,
  10. }
  11. // Struct Children
  12. #[derive(RustcDecodable, RustcEncodable)]
  13. #[derive(Debug)]
  14. struct Children {
  15. name: String,
  16. age: u8,
  17. school: String,
  18. }
  19. fn main() {
  20. let person = Parent {
  21. name: "Li".to_string(),
  22. age: 35,
  23. children: Children {
  24. name: "Li's son".to_string(),
  25. age: 8,
  26. school: "primary".to_string(),
  27. },
  28. };
  29. println!("no children==>{:#?}", person); // 可以打印出来person
  30. let to_json_str = json::encode(&person).unwrap();
  31. println!("json str==>{}", to_json_str);
  32. }

39. struct 转普通字符串

也只能参考struct 转 json 字符串

40. 可省略的struct

41. 禁用无效代码检查

[allow(dead_code)]

42. 匿名函数 TODO

Rust 使用闭包(closure) 来创建匿名函数

  1. let num=5;
  2. let plus_num= |x:i32| x +num;

闭包plus_num借用了它的作用域中的let 绑定num,如想让闭包获取所有权,可以使用move关键字:

  1. let mut num=5;
  2. {
  3. let mut add_num=move |x:i32| num+=x; // 闭包通过move 获取num所有权
  4. add_num(5)
  5. }

43. 如何合并多个结构?

  1. fn get_merge_config() {
  2. let default_config = get_default_config();
  3. let outside_config= get_outside_config();
  4. let merge_config=ConfigModule{
  5. default_config, // TODO ??
  6. ..outside_config
  7. };
  8. println!("default config===>{:#?}", default_config);
  9. return merge_config;
  10. }

44. 如何简写if 或操作

  1. // TODO 如何简写一下代码?
  2. fn main() {
  3. let a = String::from("aa");
  4. let b = String::from("bb");
  5. // let c: String = a | b;
  6. let c;
  7. if a.len() > 0 {
  8. c = a
  9. } else {
  10. c = b
  11. }
  12. println!("{}", c);
  13. }

structures 结构

rust 通过自定义类型主要通过以下两个关键形成:

  • struct 声明一个结构
  • enum 声明一个枚举

常量可以通过const static 关键字声明

  1. - const x = 99; 不合适。x推荐大写
  2. - const X=8;错误,X虽然大写,但需要声明数据类型
  3. - const X:u32=999
  4. - const mut X:u32=99 常量不接受可变量修饰符

结构:

  • 元组结构,基本上是命名为元组的。
  • 经典的C结构
  • 无字段的单元结构对于泛型很有用
  • rust 的结构和解构

    1. struct Pair(i32,f32);
    2. struct Person<'a> {
    3. name: &'a str,
    4. //这是啥子?
    5. age: u8,
    6. }
    7. fn main(){
    8. let pair =Pair(99,99.9);
    9. let Pair{x,y}=pair; //todo ??
    10. println!("{:?}\n{:?}",x,y);
    11. let name = "Jogel";
    12. let age = 27;
    13. let jogel = Person { name, age };
    14. println!("{:?}",jogel);
    15. }
  • 如何跨文件使用use
    ```rust

enum Status{
Rich,
Poor
}
enum Work{
Google,
Microsoft,
}

use Status::{Poor,Rich};

use Work::*;

  1. ## 定时器
  2. ```rust
  3. use std::thread;
  4. use std::time::Duration;
  5. fn main() {
  6. let mut x = 1;
  7. while x < 10 {
  8. println!("{},{}",x,"哈哈哈哈");
  9. x += 1;
  10. thread::sleep(Duration::from_millis(1000));
  11. }
  12. println!("{},{}",x,"哦哦哦");
  13. }

内存和分配

堆栈;

  • 堆栈存储器

    • 循环放置
    • 相反顺序移除
    • 遵从后进先出,进电梯 原则
    • 始终 首先删除最后插入的数据
    • 堆栈内存有组织的内存,比堆内存更快
    • 访问内存的方式
    • 编译时数据大小未知,则堆内存用于存储内容
  • 堆内存

    • 堆内存是有组织的内存
    • os 在堆内存中找到一个空的空格并返回一个指针,这叫 在对上分配

内存图片;

  • 第一步
    • 向量v1与值 1 2 3 ‘666’绑定,四个部分组成
    • 指向存储器中指向存储在内存的数据的指针 长度和向量的容量
    • 这部分存储在堆栈中,二数据存储在堆内存中

one;

  • 第二步
    • v1 向量分配给向量v2
    • 指针,长度、容量将复制到堆栈中
    • 但不会讲数据复制到堆内存中
    • v1v2 都超出范围时,两者都会尝试释放内存
    • 这会导致双重空闲内存,从而使得内存损坏~

two;

  • 第三步
    • rust 避免了第二步的内存问题
    • rust没有复制分配的内存,则认为v1向量不再有效
    • v1超出范围时,它不需要释放v1的内存

three;

  1. fn main(){
  2. let v1= vec![1,2,3,"666"];
  3. let v2 = v2;
  4. }

特征复制

  • 复制特征是特殊的注释
  • 放在存储堆栈上的整数类型上
  • 如果类型使用了复制特征,则复制之后还可以使用旧变量
  • 复制类型
    • 所有整数类型,如 u32
    • 布尔类型 bool:true, false
    • 所有浮动类型,如f64
    • 字符类型,如 char

所有权和函数

所有权(ownership)【重点】

管理计算机内存的方式

  • 垃圾回收机制
    • javascript
    • java
  • 手动分配和释放内存
    • C语言
  • 所有权系统管理内存
    • Rust

堆栈知识

编译器在编译时会根据一系列的规则进行检查,runtime,ownership 所有权系统的任何功能不会减慢程序

  • 阮一峰:汇编语言入门教程

  • Heap(堆):程序运行时产生,用户去申请的,存储值

    • 缺乏组织性
    • 大小未知
    • 手动请求和分配一块区域存储数,返回地址的指针:这个过程叫:在堆上分配内存
  • Stack(栈):push、pop 等相关,函数运行时而临时占用的内存区域。后进先出(叠盘子)

  • 访问堆上的数据比访问栈上的数据慢,因为必须通过指针来访问

  • 调用函数,传递函数的值(可能是堆上数据的指针)和函数局部变量被压入栈中,当函数结束时,这些值被移除栈。

    关于rust 所有权的描述

rust的所有权操作,属于新的概念。

常识

name desc
.rs rust文件后缀
Cargo.lock
Cargo.toml
xxx.iml
src目录 源码
target目录
mnt i i是可以更改变量,可变变量
双引号 给字符/对象
str String::from(“a string”)
char a,单引号是一个单字符,超出则编译错误 let char = 'a'
&str abd,双引号括住是多个字符 let a="你好"
return None
return true
return false
return Err(err)
impl
符号整数 i开头
无符号整数 u开头,不是负号
#[derive(Debug)]
#[allow(dead_code)]
{:?} 打印数组、元组
match rust关键字提供匹配模式,类似C的 switch 参考https://doc.rust-lang.org/rust-by-example/flow_control/match.html
_ 下划线 _=>print!(“xx”),类似如果下划线在match中,类似switch 的default:

定义/结论

  • rust 变量默认不可改变,如需改变,则需要let mut bar=”hello world”
  • let mut foo = String::new() new 是String类型的关联函数,针对类型实现的,常称:静态方法
  • new 创建类型实例的惯用函数名
  • Result 类型是枚举,枚举(enums),它的值被称为枚举的成员(variants):ok,Err
    • ok 表示成功
    • Error 表示失败
  • io::Result,的实例拥有expect方法,return 的是一个 输入的字节数usize
  • rust标准库中尚未包含随机数功能,rust团队提供了 rand crate
  • std::cmp::Ordering类型,Ordering也是一个枚举,成员是Less(小于),Greater(大于),Equal(等于),比较两个值的三种结果
  • //#[derive(Debug)]的//去掉时能自动为Student实现std::fmt::Debug特性。
  • use 枚举名称::*,自动列出枚举名称的名称,少写几次枚举名称,直接写成员
    ```text
    enum Work{
    1. Google,
    2. Microsoft,
    3. Alibaba=999
    }
    use Work::*;
    let work = Google;
    let worker =Microsoft;
    let taobao =Alibaba;//??
  1. - rust 使用 snake case 风格,所有字母都小写并使用下划线分割
  2. - rust 函数声明提升,无论声明在调用之前或之后
  3. - rust 函数的参数必须有类型fn test(arg1:i32,arg2:u64)
  4. - rust 是一门基于表达式的语言(expression-based)
  5. - rust 无法使用`x=y=6`
  6. ### 常量和变量的区别
  7. - let 变量
  8. - let x =6 不可变的变量
  9. - let mut x=6 自动推断类型,且可变
  10. - const 常量,大写
  11. - const x = 99; 不合适。x推荐大写
  12. - const X=8;错误,X虽然大写,但需要声明数据类型
  13. - const mut X:u32=99 常量不接受可变量修饰符
  14. - const X:u32=999
  15. ### 隐藏,shadowing
  16. 重复声明的方式来达到变量替换的目的,后者会替换前面的变量
  17. ```rust
  18. fn main(){
  19. let mut x = 666;
  20. let x =999;
  21. let mut x = 888;//此处的mut 是多余了
  22. }

install

version

rustc —version

update 更新

rustup update

uninstall 下载

rustup self uninstall

demo

处理一次猜测

  • 处理一次猜测
    ```rust
    use std::io;
    fn main(){
    println!(“hello world”);
    let mut guess =String::new(); //?干嘛的,空字符串
    println!(“请输入:{}”,guess);

    io::stdin().read_line(&mut guess)

    1. .expect("读取行失败");

    println!(“你猜的,{}”,guess);
    }

  1. ### 猜到对数字
  2. ```toml
  3. [package]
  4. name = "learn-rust"
  5. version = "0.1.0"
  6. authors = ["veaba"]
  7. edition = "2018"
  8. [dependencies]
  9. rand="0.3.14"
  1. /**
  2. @desc 步骤分析:
  3. 1、生成一个1-100的随机数
  4. 2、键盘输入一值
  5. 3、loop循环
  6. 4、比较大小
  7. */
  8. use std::io;
  9. use rand::Rng;
  10. use std::cmp::{Ordering,Ord};
  11. fn main() {
  12. let code = rand::thread_rng().gen_range(1,101);
  13. println!("code:{}",code);
  14. loop {
  15. println!("======== 请输入你的字符 ========");
  16. let mut key=String::new();//生成一个类型为String的实例
  17. io::stdin().read_line(&mut key)
  18. .expect("输入错误~");
  19. println!("你输入的:{}",key);
  20. // rust 允许用一个新值来隐藏(shadow)guess之前的值:常用于转换值类型之类的场景,
  21. // 这种用法,允许复用guess便利店个名称,而不是创建两个不同的变量
  22. // 详见:https://kaisery.github.io/trpl-zh-cn/ch03-00-common-programming-concepts.html
  23. let key:u32=match key.trim().parse(){
  24. Ok(num)=>num,
  25. Err(_)=>{
  26. println!("字符类型不对");
  27. continue
  28. }
  29. };
  30. // key 和code 没办法对比,请改为CMP->cmp
  31. match key.CMP(&code) {
  32. Ordering::Less=>println!("太小了"),
  33. Ordering::Greater=>println!("太大了"),
  34. Ordering::Equal=>{
  35. println!("猜中了,biubiu");
  36. break;
  37. }
  38. }
  39. }
  40. }

rustup

cargo

第一个程序

  1. fn main(){
  2. print!("Hello,world!");
  3. }

执行命令

rustc hello.rs

会生成hello.exehello.pdb,windows 下运行hello.exe才会运行

函数

函数 解释 demo
format!() 格式化文本写入字符串
print! 类似format!,但打印到控制台
println!()类似print!但会添加新的一行
eprint! 类型format!,打印为标准错误
eprintln!()类似eprint,但会添加新的一行
  1. // ->指返回
  2. fn add_one(x:i32)->i32{
  3. x+1
  4. }
  5. // todo 问号是干嘛的?fs::write("foo.txt","哈哈哈")?;
  6. // let _ = fs::write("foo.txt", "哈哈哈");

函数发散,不会返回

系统/全局函数或方法

print!()

  • print!(双引号),且只能是字符串
  1. fn main(){
  2. let a=9;
  3. if a==9 {
  4. print!("aaa");
  5. }
  6. }

println!()

  1. println!("{}","xxx");
  2. println!("{:?}",xxx);

.to_owned()

.iter()

match 类似 switch

  1. fn main(){
  2. let number=1;
  3. println!("the number:{}",number);
  4. // prime
  5. match number {
  6. 1=>println!("One"),
  7. 2=>println!("Two"),
  8. 3|4|5|6|7|11=>println!("匹配的数字"),
  9. 12...19=>println!("A ten哇"),
  10. // 不是特殊的
  11. _=>println!("default"),
  12. }
  13. let boolean =true;
  14. let binary =match boolean
  15. {
  16. false=>0,
  17. true=>1
  18. };
  19. println!("{}-{}",boolean,binary);
  20. }

if判断语句

  1. fn main(){
  2. let a=9;
  3. if a==8 {
  4. println!("aaa");
  5. }
  6. else if a>8 {
  7. println!("bbb");
  8. }
  9. else{
  10. println!("ccc");
  11. }
  12. }

if in a let语句

错误处理error

expected integer, found char

too many characters in char literal 表示只能是单个字符!!a或者b,不能ab

String::from(“S/\q\t\nI}POYY?M>NM>M<JKLKL:KLII/\dh”) \d这里有问题

循环

loop 循环

  • 需要mnt 声明变量,
  • 无法使用i++ 自增加1,而是i+=1
  • break 跳出loop
    ```rust
    fn main(){
    let mut i =1;
    loop {
    1. println!("{}",i);
    2. if i==10{
    3. break
    4. }
    5. i+=1
    }
    }
  1. ### for循环
  2. - 循环数组
  3. ```rust
  4. // 循环数组
  5. fn main(){
  6. let res =["mango","apple","banana","litchi","watermelon"];
  7. for i in res.iter() { //iter()方法
  8. println!("{}",i)
  9. }
  10. }
  • 循环对象
    1. //TODO 循环对象

    while循环

  • 索引不正确,循环有问题
  • 每次迭代前进行条件检查,速度慢
  • 如果外部引发条件变化,则可能会引发死循环的异常
    1. fn main(){
    2. let mut i=0;
    3. while i<=10 {
    4. println!("{}",i);
    5. i+=1
    6. }
    7. }

    字符串 string

rust 有两种主要的字符串类型 &strString

&str 字符串片段(string slices)

&'static str 字符串常量

  1. // &'static str 的返回值
  2. fn main(){
  3. println!("一个函数返回一个字符串:{}",return_a_string());
  4. }
  5. fn return_a_string()->(&'static str){
  6. let str = "哇哈哈哈";
  7. return str
  8. }

数组

  • 数组每个元素的类型必须相同
  • 不可减少长度或者增加长度

访问方式 和js 一样 arr[1]

数组的函数/方法

vector 可伸缩的数组

  • 标准库提供的一个允许增长和缩小长度的类似数组的集合类型

所有权

  • 代码块拥有资源时,被称为所有权。
  • 代码块创建一个包含资源的对象。
  • 当控件到达末尾时,对象将被销毁,资源将被释放
  • Rust中,每个值都有一个与之关联的变量,并成为其所有者
  • 一次只能有一个所有者
  • 当所有者超出范围是,与其关联的值将被销毁

a被回收,编译直接报错

  1. //
  2. fn main(){
  3. let a =20;
  4. let b = a;
  5. println!("{}",a)
  6. }

但是 下面这样就不会被回收~~ TODO ?why?

  1. fn main1(){
  2. let a =20;
  3. let b = a;
  4. println!("{}",b);
  5. println!("{}",a)
  6. }

所有权和函数

  1. fn main(){
  2. let s =String::from("SDUSAJDOISAJ IUJODSJAI ");//啥意思?
  3. take_ownership(s);
  4. let ch ='a';
  5. move_copy(ch);
  6. println!("main:{}",ch)
  7. }
  8. fn take_ownership(str:String){
  9. println!("take_ownership:{}",str)
  10. }
  11. fn move_copy(c:char){
  12. println!("move_copy:{}",c)
  13. }
  • 字符

    ```rust
    fn main(){
    let ch = ‘a’;
    //let tt = ‘abad’;//为啥这里会报错,因为char 类型只能是一个字符
    move_copy(ch);
    move_copy(tt);
    }

fn move_copy(str:String){
println!(“{}”,str)
}

  1. ### 存放任意字符,斜杠之类的
  2. > \d \q都有问题
  3. >let s =String::from("S/\q\t\nI}POYY<M?>?M>NM>M<JKLKL:KLII//\dh");
  4. ## 字符串函数/方法
  5. ### len() 取长度
  6. ```rust
  7. fn main(){
  8. let x = 999;
  9. println!("{}",x.len()); //错误
  10. let y ="66";
  11. println!("{}",y.len());
  12. }

trim() 移除首尾字符

  1. fn main(){
  2. let str1 = "\n 444";
  3. println!("{}",str1.trim());
  4. }

.parse() 转为数字类型,并且会返回一个枚举,含有两个成员,ok和 err类型

.expect(‘msg’)一般处理异常抛出的结果

fs

  1. use std::fs;
  2. fn write_file() -> std::io::Result<()> {
  3. fs::write("foo.txt","哈哈哈")?;
  4. Ok(())
  5. }
  6. fn main() {
  7. println!("hello world");
  8. let _ = write_file();
  9. }

数据类型

类型
布尔类型 true false
字符类型 单个Unicode类型,存储4个字节
数值类型-符号整数 i8 i16 i32 i64 isize
数值类型-无符号整数 u8 u16 u32 u64 usize
数值类型-浮点数 f32 f64
字符串类型-底层不定长类型 str
字符串类型-字符串切片 &str,静态分配,固定大小,不可变
字符串类型-堆分配字符串 String,可变
数组 固定大小,且元素都同类型,[T;N]
切片 引用一个数组的部分数据,并且不需要拷贝,&[T]
元组 固定大小的有序列表,元素都有自己的类型,通过解构或者索引来获取值
指针 最底层的裸指针,*const T *mut T,但解引用它们是不安全的,必须放到unsafe块里
函数 具有函数类型的变量实质上是一个函数指针
元类型 (),其唯一值也是()

标量类型

  • 整型。没有小数部分的数字,默认i32

rust中的整型

长度 有符号 无符号(负数) -(2n-1 -1)
8-bit i8 u8
16-bit i16 u16
32-bit i32 u32
64-bit i64 u64
arch isize usize

isizeusize 类型依赖计算机架构,64位是64位,32位是32位

rust中的整型字面值

数字字面值 例子
Decimal 98_222
Hex 0xff
Octal 0o77
Binary 0b1111_0000
byte (u8 only) bA

整型溢出u8 放到0-255值,修改为256,被称为整型溢出(idnteger overflow)

在 release 构建中,Rust 不检测溢出,相反会进行一种被称为 “two’s complement wrapping” 的操作。简而言之,256 变成 0,257 变成 1,依此类推。依赖溢出被认为是一种错误,即便可能出现这种行为。如果你确实需要这种行为,标准库中有一个类型显式提供此功能,Wrapping。

  • 浮点型。带小数点的数字,有两个原生的浮点数类型f32f64,默认f64。IEEE-754标准
    • f32 单精度浮点数
    • f64 双精度浮点数
      ```rust
      fn main(){
      let x = 2.0; // f64
      let y:f32= 3.2; //f32

}

  1. - `布尔型`bool
  2. - true
  3. - false
  4. - `字符类`
  5. - `char`代表Unicode,单个字符,中文或者其他语言的单字
  6. ### 复合类型
  7. - tuple `(a,b,c,d)`
  8. - array `[a,b,c,d]`
  9. ### 基本类型
  10. |类型|最小值|最大值|值|描述|所属组|
  11. |---|---|---|---|---|---|
  12. |array||||1||
  13. |bool||||||
  14. |char||||||
  15. |f32||||||
  16. |f64||||||
  17. |fn||||||
  18. |i8||||||
  19. |i16||||||
  20. |i32||||||
  21. |i64||||||
  22. |i128||||||
  23. |isize||||||
  24. |never||||||
  25. |pointer||||||
  26. |reference||||||
  27. |slice||||||
  28. |str||||||
  29. |tuple||||||
  30. |u8||||||
  31. |u16||||||
  32. |u32||||||
  33. |u64||||||
  34. |u128||||||
  35. |unit||||||
  36. |usize||||||
  37. > https://doc.rust-lang.org/nightly/std/primitive.i8.html
  38. ### 数字转为其他类型
  39. ## rustup
  40. Command | Description
  41. ----------------------------------------------------------- | ------------------------------------------------------------
  42. `rustup default nightly` | Set the default toolchain to the latest nightly
  43. `rustup target list` | List all available targets for the active toolchain
  44. `rustup target add arm-linux-androideabi` | Install the Android target
  45. `rustup target remove arm-linux-androideabi` | Remove the Android target
  46. `rustup run nightly rustc foo.rs` | Run the nightly regardless of the active toolchain
  47. `rustc +nightly foo.rs` | Shorthand way to run a nightly compiler
  48. `rustup run nightly bash` | Run a shell configured for the nightly compiler
  49. `rustup default stable-msvc` | On Windows, use the MSVC toolchain instead of GNU
  50. `rustup override set nightly-2015-04-01` | For the current directory, use a nightly from a specific date
  51. `rustup toolchain link my-toolchain "C:\RustInstallation"` | Install a custom toolchain by symlinking an existing installation
  52. `rustup show` | Show which toolchain will be used in the current directory
  53. `rustup toolchain uninstall nightly` | Uninstall a given toolchain
  54. `rustup toolchain help` | Show the `help` page for a subcommand (like `toolchain`)
  55. `rustup man cargo` | \(*Unix only*\) View the man page for a given command (like `cargo`)
  56. ## Cargo
  57. - https://rustlang-cn.org/office/rust/cargo/getting-started/installation.html
  58. ### 安装Cargo
  59. > curl https://sh.rustup.rs -sSf | sh
  60. 如果顺利则:
  61. > Rust is installed now. Great!
  62. ### Cargo 第一步
  63. 创建项目:
  64. > cargo new helloworld
  65. build
  66. >cargo build
  67. 运行
  68. >./target/debug/helloworld
  69. cargo run
  70. >cargo run
  71. cargo doc --open 生成并打开一个文档,构建所有本地依赖提供的文档。帅!
  72. >cargo doc --open
  73. ### cargo 指南
  74. 为什么会有cargo
  75. - 引入两个带有各种程序包信息的元数据文件
  76. - 获取和构建项目依赖
  77. - 正确的构建参数调用rustc 和其他构建工具
  78. - 引入惯例使得rust程序包开发管理更加容易
  79. 已存的cargo项目
  80. ```cmd
  81. git clone xx
  82. cd xx
  83. cargo build

一个cargo依赖如何添加

  1. [dependencies]
  2. time="0.1.12"

cargo build 会获取新的依赖以及依赖的依赖,一并编译。并且更新Cargo.lock文件

cargo update 更新依赖

cargo 项目结构:

  1. .
  2. ├── Cargo.lock 具体依赖信息,cargo维护,不应该手动修改,可防止.gitignore文件
  3. ├── Cargo.toml 广义上秒数项目的依赖文件,开发者编写
  4. ├── benches 性能评估
  5. └── large-input.rs
  6. ├── examples 示例目录
  7. └── simple.rs
  8. ├── src 源码
  9. ├── bin
  10. └── another_executable.rs
  11. ├── lib.rs 库文件
  12. └── main.rs 默认可执行文件源代码
  13. └── tests 单元测试
  14. └── some-integration-tests.rs

cargo toml 清单文件

  1. [package]
  2. name = "hello_world"
  3. version = "0.1.0"
  4. authors = ["Your Name <you@example.com>"]
  5. [dependencies]
  6. # 指定依赖仓库
  7. rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
  8. # 解决指定版本,没多卵用。
  9. rand = { git = "https://github.com/rust-lang-nursery/rand.git", rev = "9f35b8e" }

cargo update 更新所有依赖

cargo update -p rand 仅更新rand

cargo test

  • src 目录下每个文件中的 tests/目录,单元测试
  • test/目录是集成风格的测试
  • cargo test 会运行额外的检查
  • 参考文档https://doc.rust-lang.org/book/testing.html

    可执行指定参数测试,将测试名称含有foo的所有测试

    carto test foo

cargo 持续集成

Travis CI 测试项目

  • 测试所有三个发布通道
  • 任何nightly构建中断将不会使整体构建失败
  • 参考 Travic CI Rust documentation https://docs.travis-ci.com/user/languages/rust/
    1. language:rust
    2. rust:
    3. - stable
    4. - beta
    5. - nightly
    6. matrix:
    7. allow_failures:
    8. - rust :nightly

GitLab CI

  • stable 通道 和 nightly 通道测试
  • 任何nightly构建中断将不会使整体构建失败
  • Gitlab CI https://docs.gitlab.com/ce/ci/yaml/README.html
    ```yml
    stages:
    • build
      rust-latest:
      stage:build
      image:rust:latest
      script:
      • cargo build —verbose
      • cargo test —verbose

rust-nightly:
statge:build
image:rustlang/rust:nightly
script:

  1. - cargo build --verbose
  2. - cargo test --verbose
  3. allow_failure:true
  1. #### build.sr.ht
  2. - 确保将`<your repo>``<your project>`改变为要克隆和已克隆的目录。
  3. - 将会在stablenightly通道测试和构建文档
  4. - 但是任何nightly构建中断将不会使整体构建失败
  5. - 参考builds.sr.ht documentation https://man.sr.ht/builds.sr.ht/
  6. ```yml
  7. image: archlinux
  8. packages:
  9. - rustup
  10. sources:
  11. - <your repo>
  12. tasks:
  13. - setup: |
  14. rustup toolchain install nightly stable
  15. cd <your project>/
  16. rustup run stable cargo fetch
  17. - stable: |
  18. rustup default stable
  19. cd <your project>/
  20. cargo build --verbose
  21. cargo test --verbose
  22. - nightly: |
  23. rustup default nightly
  24. cd <your project>/
  25. cargo build --verbose ||:
  26. cargo test --verbose ||:
  27. - docs: |
  28. cd <your project>/
  29. rustup run stable cargo doc --no-deps
  30. rustup run nightly cargo doc --no-deps ||:

cargo构建缓存

cargo 依赖指定

  1. [dependencies]
  2. rand = { git = "https://github.com/rust-lang-nursery/rand" }
  3. # 指定分支
  4. [dependencies]
  5. rand = { git = "https://github.com/rust-lang-nursery/rand", branch = "next" }
  6. # 路径依赖指定
  7. [dependencies]
  8. hello_utils = { path = "hello_utils" }
  9. # 发布cargo箱子
  10. [dependencies]
  11. hello_utils = { path = "hello_utils", version = "0.1.0" }

cargo 清单格式 TODO

cargo 环境变量 TODO

cargo 构建脚本

cargo 发布依赖到crates.io

cargo 词汇表

cargo 错误

Blocking waiting for file lock on the registry index

解决: rm -rf ~/.cargo/registry/index/*

rust redis

rust mongo