├── .gitignore ├── Cargo.toml ├── README.md ├── note ├── README.md ├── chapter1 │ ├── 01.md │ ├── 02.md │ ├── 03.md │ ├── 04.md │ ├── 05.md │ ├── 06.md │ ├── 07.md │ ├── 08.md │ ├── 09.md │ ├── 10.md │ ├── 11.md │ ├── 12.md │ ├── 13.md │ ├── 14.md │ ├── 15.md │ ├── 16.md │ ├── 17.md │ ├── 18.md │ ├── 19.md │ ├── 20.md │ ├── 21.md │ ├── 22.md │ ├── 23.md │ ├── 24.md │ ├── 25.md │ ├── 26.md │ ├── 27.md │ ├── 28.md │ ├── 29.md │ ├── 30.md │ ├── 31.md │ └── img │ │ ├── 08copy.png │ │ ├── 08move.png │ │ ├── 09datatype.png │ │ └── 24cargo.png └── chapter2 │ ├── 32.md │ ├── 33.md │ ├── 34.md │ ├── 35.md │ └── img │ ├── 32.png │ ├── 33.png │ └── 34-1.png ├── src ├── ch01 │ ├── lexical.rs │ └── mod.rs ├── demo │ ├── 06.rs │ ├── 09.rs │ ├── 09_turbefish.rs │ ├── 10.rs │ ├── 11.rs │ ├── 15.rs │ ├── 22.rs │ ├── 35.rs │ ├── toml-demo-refactor │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── README.md │ │ ├── bin │ │ │ └── main.rs │ │ ├── config │ │ │ └── Poem.toml │ │ └── src │ │ │ ├── conf.rs │ │ │ ├── conf │ │ │ ├── basic_config.rs │ │ │ ├── error.rs │ │ │ └── poem_config.rs │ │ │ ├── environment.rs │ │ │ └── lib.rs │ └── toml-demo │ │ ├── Cargo.toml │ │ ├── conf │ │ └── Poem.toml │ │ └── src │ │ ├── conf.rs │ │ ├── environment.rs │ │ ├── error.rs │ │ └── main.rs └── lib.rs └── tutorial ├── firstclass ├── 10 │ ├── lifetime.rs │ ├── max.rs │ └── strtok.rs ├── 11 │ ├── enum.rs │ ├── struct.c │ └── struct.rs ├── 12 │ ├── const.rs │ ├── homework.rs │ ├── id.rs │ ├── map.rs │ ├── readfile.rs │ ├── turbofish.rs │ └── var.rs ├── 13 │ └── trait_tutorial │ │ ├── Cargo.toml │ │ └── src │ │ ├── animal.rs │ │ ├── main.rs │ │ └── parser.rs ├── 14 │ ├── clone_trait.rs │ ├── debug.rs │ └── ipadrr.rs ├── 01 │ └── 01.rs ├── 02 │ ├── 02.c │ └── 02.rs ├── 03 │ ├── fib.rs │ ├── func.rs │ ├── return.rs │ ├── scrape_url │ │ ├── Cargo.toml │ │ ├── rust.md │ │ └── src │ │ │ └── main.rs │ ├── struct.rs │ └── test_tutorial │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── 04 │ └── HTTPie │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── 05 │ └── thumbor │ │ ├── Cargo.toml │ │ └── src │ │ └── main.rs ├── 06 │ └── queryer │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── 07 │ └── find_pos.rs ├── 08 │ ├── local_ref.rs │ ├── local_vec.rs │ └── sum.rs └── 09 │ ├── dag.rs │ └── rc.rs └── rustlings └── exercises ├── README.md ├── advanced_errors ├── advanced_errs1.rs └── advanced_errs2.rs ├── clippy ├── README.md ├── clippy1.rs └── clippy2.rs ├── collections ├── README.md ├── hashmap1.rs ├── hashmap2.rs ├── vec1.rs └── vec2.rs ├── conversions ├── README.md ├── as_ref_mut.rs ├── from_into.rs ├── from_str.rs ├── try_from_into.rs └── using_as.rs ├── enums ├── README.md ├── enums1.rs ├── enums2.rs └── enums3.rs ├── error_handling ├── README.md ├── errors1.rs ├── errors2.rs ├── errors3.rs ├── errors4.rs ├── errors5.rs └── errors6.rs ├── functions ├── README.md ├── functions1.rs ├── functions2.rs ├── functions3.rs ├── functions4.rs └── functions5.rs ├── generics ├── README.md ├── generics1.rs ├── generics2.rs └── generics3.rs ├── if ├── README.md ├── if1.rs └── if2.rs ├── macros ├── README.md ├── macros1.rs ├── macros2.rs ├── macros3.rs └── macros4.rs ├── modules ├── README.md ├── modules1.rs ├── modules2.rs └── modules3.rs ├── move_semantics ├── README.md ├── move_semantics1.rs ├── move_semantics2.rs ├── move_semantics3.rs ├── move_semantics4.rs └── move_semantics5.rs ├── option ├── README.md ├── option1.rs ├── option2.rs └── option3.rs ├── primitive_types ├── README.md ├── primitive_types1.rs ├── primitive_types2.rs ├── primitive_types3.rs ├── primitive_types4.rs ├── primitive_types5.rs └── primitive_types6.rs ├── quiz1.rs ├── quiz2.rs ├── quiz3.rs ├── quiz4.rs ├── standard_library_types ├── README.md ├── arc1.rs ├── box1.rs ├── iterators1.rs ├── iterators2.rs ├── iterators3.rs ├── iterators4.rs └── iterators5.rs ├── strings ├── README.md ├── strings1.rs └── strings2.rs ├── structs ├── README.md ├── structs1.rs ├── structs2.rs └── structs3.rs ├── tests ├── README.md ├── tests1.rs ├── tests2.rs └── tests3.rs ├── threads ├── README.md └── threads1.rs ├── traits ├── README.md ├── traits1.rs └── traits2.rs └── variables ├── README.md ├── variables1.rs ├── variables2.rs ├── variables3.rs ├── variables4.rs ├── variables5.rs └── variables6.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | **/*.exe 12 | **/*.pdb 13 | **/target/* 14 | 15 | .DS_Store 16 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "inviting-rust-note" 3 | version = "0.1.0" 4 | authors = ["pxiaoer"] 5 | edition = "2018" 6 | 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust实战课程笔记 2 | 3 | 4 | 课程链接: [张汉东的Rust实战课](http://gk.link/a/10lHI) 5 | 我的Rust学习经历: [你为什么要学习Rust](https://mp.weixin.qq.com/s/WS2kikpuHKGxPJ_UBfYhgg) 6 | 7 | 8 | ## Rust入门资料 9 | 10 | - [Rust官方文档](https://prev.rust-lang.org/zh-CN/documentation.html) 11 | - Rust入门书 12 | - [Rust程序设计](https://union-click.jd.com/jdc?e=&p=AyIGZRprFQEaAVUcXBQyVlgNRQQlW1dCFFlQCxxKQgFHREkdSVJKSQVJHFRXFk9FUlpGQUpLCVBaTFhbXQtWVmpSWRtYHQQSAFIaa2d8Un00fSRjZ3VDN34ndHFhYxRpAUMOHjdUK1sUAxAHVxNYFgsiN1Uca0NsEgZUGloUBxYAUitaJQIVBlUaWhACGgNcGlMlBRIOZUAOe1ZyTjx4J11pamAFXWslMhE3ZStbJQEiRTtMWxxXEVdRHQ5GBBYCARoLHFdFVwBPXEcBQg4HTFISAiIFVBpfHA%3D%3D) 13 | - [Rust编程之道](https://union-click.jd.com/jdc?e=&p=AyIGZRprFQEXAV0eWxEyVlgNRQQlW1dCFFlQCxxKQgFHREkdSVJKSQVJHFRXFk9FUlpGQUpLCVBaTFhbXQtWVmpSWRtYEAQaAlUfa21hdA8ybCR0YhBHXW0ya3lgAgFDC0MOHjdUK1sUAxAHVxNYFgsiN1Uca0NsEgZUGloUBxICVitaJQIVBlUaWhACEQFSGF4lBRIOZUAOe1ZyTjx4J11pamAFXWslMhE3ZStbJQEiRTsYCEUAFQJUGFsVChQCBhlfHFYXBFxMW0ZQRQMFE1kSViIFVBpfHA%3D%3D) 14 | - [Stanford CS 110L](https://github.com/xxg1413/CS110L) 15 | 16 | 17 | ## 目录 18 | 19 | - [01 | 课程介绍](./note/chapter1/01.md) 20 | - [02 | 内容综述](./note/chapter1/02.md) 21 | - [03 | Rust语言学习观](./note/chapter1/03.md) 22 | - [04 | Rust语言概览](./note/chapter1/04.md) 23 | - [05 | 语法面面观:词法结构](./note/chapter1/05.md) 24 | - [06 | 语法面面观:面向表达式(上)](./note/chapter1/06.md) 25 | - [07 | 语法面面观:面向表达式(中)](./note/chapter1/07.md) 26 | - [08 | 语法面面观:面向表达式(下) ](./note/chapter1/08.md) 27 | - [09 | 语法面面观:数据类型 (上)](./note/chapter1/09.md) 28 | - [10 | 语法面面观:数据类型 (下)](./note/chapter1/10.md) 29 | - [11 | 语法面面观:函数与闭包(上)](./note/chapter1/11.md) 30 | - [12 | 语法面面观:函数与闭包(中)](./note/chapter1/12.md) 31 | - [13 | 语法面面观:函数与闭包(下)](./note/chapter1/13.md) 32 | - [14 | 语法面面观:模式匹配](./note/chapter1/14.md) 33 | - [15 | 语法面面观:智能指针(上)](./note/chapter1/15.md) 34 | - [16 | 语法面面观:智能指针(下)](./note/chapter1/16.md) 35 | - [17 | 语法面面观:字符与字符串(上)](./note/chapter1/17.md) 36 | - [18 | 语法面面观:字符与字符串(下)](./note/chapter1/18.md) 37 | - [19 | 语法面面观:集合容器(上)](./note/chapter1/19.md) 38 | - [20 | 语法面面观:集合容器(下)](./note/chapter1/20.md) 39 | - [21 | 语法面面观:迭代器(上)](./note/chapter1/21.md) 40 | - [22 | 语法面面观:迭代器(下)](./note/chapter1/22.md) 41 | - [23 | Rust语法面面观:模块](./note/chapter1/23.md) 42 | - [24 | Rust语法面面观:Cargo包管理器(上)](./note/chapter1/24.md) 43 | - [25 | Rust语法面面观:Cargo包管理器(下)](./note/chapter1/25.md) 44 | - [26 | 语法面面观:实际项目的组织结构(上)](./note/chapter1/26.md) 45 | - [27 | 语法面面观:实际项目的组织结构(下)](./note/chapter1/27.md) 46 | - [28 | 语法面面观:定义自己的Crate(上)](./note/chapter1/28/md) 47 | - [29 | 语法面面观:定义自己的Crate(中)](./note/chapter1/29.md) 48 | - [30 | 语法面面观:定义自己的Crate(下)](./note/chapter1/30.md) 49 | - [31 | 作业&第二章预告](./note/chapter1/31.md) 50 | - [32 | 本章内容介绍:Rust语言架构](./note/chapter2/32.md) 51 | - [33 | 所有权:内存管理基础知识](./note/chapter2/33.md) 52 | - [34 | 所有权:安全管理之内存安全 ](./note/chapter2/34.md) 53 | - [35 | 所有权:Copy语义和Copy trait](./note/chapter2/35.md) 54 | 55 | 56 | 57 | 58 | 59 | ## 源码分析 60 | 61 | 0. [gping](https://github.com/orf/gping)源码分析 62 | 1. tokenizers源码分析 63 | 2. ann-rs源码分析 64 | 3. smartcore源码分析 65 | 66 | [Rust 源码阅读俱乐部](https://github.com/ZhangHanDong/rust-code-reading-club) 67 | 68 | 69 | ## Rust安全 70 | 71 | - [Rust-CTF](https://github.com/xxg1413/rust-ctf) 72 | - [Rust-Security](https://github.com/xxg1413/rust-security) 73 | - [Hacking-with-Rust](https://github.com/xxg1413/Hacking-with-Rust) 74 | 75 | -------------------------------------------------------------------------------- /note/README.md: -------------------------------------------------------------------------------- 1 | ## Rust实战课程笔记 2 | 3 | 4 | ## 章节 5 | 6 | - [第一章 Rust语言基础](./chapter1) 7 | - [第二章 Rust语言核心概念](./chapter2) 8 | - [第三章 Rust异步编程基础](./chapter3) 9 | 10 | 11 | -------------------------------------------------------------------------------- /note/chapter1/01.md: -------------------------------------------------------------------------------- 1 | ## 01.课程介绍 2 | 3 | 4 | ## 笔记 5 | 6 | #### 为什么要学习Rust 7 | 8 | 1. 掌握Rust语言就掌握了其他很多语言的精髓 9 | 2. 学习Rust可以帮助你突破自身的瓶颈,让自己的能力晋升到新的台阶,也抓住了时代的脉搏 10 | 3. 当下唯一一门注重安全和性能的语言 11 | 12 | #### 学习Rust关键点和难点 13 | 14 | 1. 改变之前的学习习惯,Rust会在编译期进行各种检查,需要开发者和编译器做斗争 15 | 2. 需要过5道关口 16 | - 所有权机制 17 | - 借用和生命周期 18 | - 类型系统与trait 19 | - 突破抽象范式 20 | - Unsafe Rust 21 | 22 | #### 课程结构 23 | 24 | 1. 语言核心概念讲解 25 | 2. 实战:编写一个轻量级的异步Web框架 26 | 27 | 28 | ## Rust语言应用的领域 29 | 30 | - 操作系统 31 | - Fuchsia 32 | - Redox 33 | - Tock 34 | 35 | - 数据库 36 | - tikv 37 | - 游戏 38 | - [Rust游戏开发2020生态圈展望](http://llever.com/2020/02/08/rust%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%912020%E7%94%9F%E6%80%81%E5%9C%88%E5%B1%95%E6%9C%9B-%E8%B0%83%E6%9F%A5%E7%BB%93%E6%9E%9C%E8%AF%91/) 39 | - 网络服务 40 | - Rocket 41 | - tokio 42 | - tarpc 43 | - brpc 44 | 45 | - Web应用 46 | - Rocket 47 | - tokio 48 | 49 | - 区块链 50 | - Rust区块链项目: parity, Polkadot, Substrate, Grin, Ethereum classic, Holochain, Cardano-rust, Exonum, Lighthouse, Nimiq, Nervos, Conflux-rust, Codechain, Witnet 51 | 52 | - 物联网 53 | - [为什么选择Rust作为物联网的编程语言?](https://www.jdon.com/52577) 54 | - 嵌入式 55 | - [rust官网嵌入式介绍](https://www.rust-lang.org/zh-CN/what/embedded) 56 | - 机器学习 57 | - huggingface/tokenizers 58 | - jieba-rs 59 | - [Rust 机器学习的现状](https://zhuanlan.zhihu.com/p/68529949) 60 | 61 | 更多案例,访问Rust官网[生产环境用户](https://www.rust-lang.org/zh-CN/production/users) -------------------------------------------------------------------------------- /note/chapter1/02.md: -------------------------------------------------------------------------------- 1 | ## 内容综述 2 | 3 | 4 | ## 课程重点 5 | 6 | 7 | - 第一章 Rust语言基础 8 | - 第二章 Rust语言核心概念 9 | - 第三章 Rust异步编程基础 10 | - 第四章 构建自己的异步Web框架 11 | - 第五章 为异步框架扩展功能 12 | - 第六章 使用异步框架开发简单的TodoList应用 13 | - 第七章 尾声 14 | 15 | 16 | 重点章节: 第二,三,四,五,六章,第四章为重中之重 17 | 18 | 19 | ## Rust异步资源 20 | 21 | - [Asynchronous Programming in Rust](https://rust-lang.github.io/async-book/) 22 | - [Rust异步编程 中文翻译](https://learnku.com/docs/async-book/2018) -------------------------------------------------------------------------------- /note/chapter1/03.md: -------------------------------------------------------------------------------- 1 | ## 03.Rust语言学习观 2 | 3 | ## 学习Rust的十条最佳建议 4 | 5 | 1. 从整体出发,不要让自己陷入细节中去 6 | 2. 抛弃一次性学会的念头,分层次递进式学习 7 | 3. 和你已知的知识建立联系 8 | 4. 学会阅读源码,从源码中学习 9 | 5. 通过主题式阅读填补知识空白 10 | 6. 时刻把握Rust设计哲学 11 | 7. 有意识的构建Rust语言的心智模型 12 | 8. 多分享多提问多交流 13 | 9. 为开源项目做贡献,锻炼自己 14 | 10. 阅读《Rust编程之道》 15 | 16 | 17 | ## Rust 入门练习 18 | 19 | 官方提供了练习资源,具体参考[rustlings](https://github.com/rust-lang/rustlings)这个项目的README 20 | 21 | 22 | -------------------------------------------------------------------------------- /note/chapter1/04.md: -------------------------------------------------------------------------------- 1 | ## 04.Rust语言概览 2 | 3 | 4 | ## Rust三问 5 | 6 | 1. Rust从哪里来 7 | 2. Rust是什么 8 | 3. Rust要到哪里去 9 | 10 | 11 | ## Rust设计哲学 12 | 13 | - 内存安全 14 | - 注重并发安全 15 | - 持续提升性能 16 | - 高度的语言一致性 17 | - 可见的实用性 18 | - 注重开发体验和学习体验 19 | - 现代化语言特性 20 | - 拥抱开源社区 21 | 22 | 23 | ## Rust是什么 24 | 25 | Rust是新时代的C语言 26 | 27 | - 通用型语言 28 | - 内存安全解决了C语言的不足 29 | - 安全无缝对接C语言 30 | - 混合范式的面向过程式语言 31 | - 和C一样,担负时代使命 32 | 33 | ## Rust到哪里去 34 | 35 | 基础设施建设 36 | 37 | -------------------------------------------------------------------------------- /note/chapter1/05.md: -------------------------------------------------------------------------------- 1 | ## 05.词法面面观:词法结构 2 | 3 | 4 | ## Rust语言版本 5 | 6 | - 语义化版本 7 | - 主版本号 不兼容API修改 8 | - 次版本号 9 | - 修订号 10 | 11 | - 发行版本 12 | - master -> Nightly 13 | - beat -> Beat 14 | - stable -> Stable 15 | 16 | - Edition版次 17 | - 2015 Edition 18 | - 2018 Edition 19 | - 2021 Edition 20 | 21 | Rust编译器管理版次: 指定edition="2018" 22 | 23 | ## 编译过程 24 | 25 | Code -> Tokens -> AST -> HIR -> MIR -> LLVM IR -> 机器码 26 | 27 | AST->HIR: 类型检查,方法查找 28 | HIR->MIR: 借用检查,优化,代码生成 29 | 30 | Rustc 更详细的文档: [Overview of the Compiler](https://rustc-dev-guide.rust-lang.org/overview.html) 31 | 32 | ## 词法结构 33 | 34 | - 关键字 35 | - 标识符 36 | - 注释 37 | - 空白 38 | - 词条 39 | - 路径 40 | 41 | #### 关键字 42 | 43 | - 严格关键字 44 | - 保留字 45 | - 弱关键字 46 | 47 | #### 词条 48 | 49 | - 语言项 50 | - 块 51 | - 语句 52 | - 表达式 53 | - 模式 54 | - 关键字 55 | - 标识符 56 | - 字面量 57 | - 生命周期 58 | - 可见性 59 | - 标点符号 60 | - 分隔符 61 | - 词条树 62 | - 属性 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /note/chapter1/06.md: -------------------------------------------------------------------------------- 1 | ## 06.语法面面观:面向表达式(上) 2 | 3 | 4 | ## 表达式和语句 5 | 6 | 每行代码都可以看作是一个语句 7 | 8 | - 声明语句 9 | - 流程控制语句 10 | - 表达式语句 11 | - 宏语句 12 | 13 | 14 | 15 | ## Rust语法的骨架 16 | 17 | - 属性 18 | - 分号 19 | - 花括号 20 | 21 | 22 | [demo](../src/demo/06.rs) 23 | 24 | 25 | 26 | ## Rust:面向表达式的语言 27 | 28 | 分号和块,是Rust语言的两个基本表达式 29 | 30 | #### 分号表达式 31 | 32 | 单元类型(空元组) 33 | 34 | :->() 35 | 36 | #### 块表达式 37 | 38 | 返回值为最后一个表达式的值 39 | 40 | #### 求值规则 41 | 42 | - 分号表达式返回值永远为自身的单元类型 43 | - 分号表达式只在块表达式最后一行才会进行求值,其他时候做为连接符存在 44 | - 快表达式只对其最后一行表达式进行求值 45 | 46 | 47 | 48 | ## 作业 49 | 50 | 1. Rust表达式中还有很多种类的表达式,课程中没有一一列举,你可以在课下把这些表达式都走查一遍。 51 | 2. 操作符都是表达式,它们都有优先级,你是否可以自行去了解一下这些操作符表达式的优先级列表呢 52 | 53 | -------------------------------------------------------------------------------- /note/chapter1/07.md: -------------------------------------------------------------------------------- 1 | ## 07.语法面面观:面向表达式(中) 2 | 3 | 4 | ## 什么是编译期计算 5 | 6 | CTFE: 编译期求值 7 | 8 | #### 两种方式 9 | 10 | 1. 过程宏 + Build脚本(build.rs) (比较完善) 11 | 2. 类似于C++中的constexpr CTFE功能 (只支持可用的子集) 12 | 13 | #### Rust CTFE 14 | 15 | 1. 常量函数 16 | 17 | const X: T = ...; 18 | 19 | 常量传播是编译器优化,和编译期计算不同。 20 | 21 | 常量上下文可以接受的表达式 22 | - const fn函数 23 | - 元组结构体 24 | - 元组的值 25 | 26 | 2. 常量泛型 27 | 28 | 29 | ## 作业 30 | 31 | 1. 使用 最新的 Rust 稳定版,尝试编写几个使用 if 、macth、loop等表达式的常量函数, 32 | 也可以尝试一下在常量函数里使用 println 宏进行打印,看看会你会发现什么? 33 | 2. 在 crates.io 中搜索到 const-sha1 库,去看它的源码实现,看它的内部是如何应用 34 | const fn 函数的。 35 | 3. 思考标准库 中 std::vec::Vec 的 new 方法,为什么是常量函数?这样做有什么好处? 36 | 4. 继续完善 ArrayVec 示例,参考: https://github.com/Michael-F-Bryan/constarrayvec -------------------------------------------------------------------------------- /note/chapter1/08.md: -------------------------------------------------------------------------------- 1 | ## 08.语法面面观:面向表达式(下) 2 | 3 | 4 | ## Rust表达式分类 5 | 6 | - 位置表达式 7 | - 值表达式 8 | 9 | 10 | #### 位置表达式 11 | 12 | - 静态变量初始化 13 | static mut LEVELS: u32 = 0; 14 | 15 | - 解引用表达式 16 | *expr 17 | 18 | - 数组索引表达式 19 | expr[expr] 20 | 21 | - 字段表达式 22 | expr.field 23 | 24 | - 以上和加上括号的位置表达式 25 | (expr) 26 | 27 | 28 | #### 值表达式 29 | 30 | 除了位置表达式,都是值表达式 31 | 32 | 33 | ## Rust所有权语义在表达式的体现 34 | 35 | - Copy 语义 36 | Copy 语义代表可以安全在栈内存复制 37 | ![](./img/08copy.png) 38 | 39 | - Move 语义 40 | Move 语义代表必须旧的绑定失效,避免内存不安全 41 | ![](./img/08move.png) 42 | 43 | 堆内存分配,栈只存储指针,赋值则所有权转移 44 | 45 | ## Rust的不可变与可变 46 | 47 | - 不可变绑定与可变绑定 48 | - 不可变引用于可变引用 49 | 50 | ## 作业 51 | 52 | 1. 除了 let 赋值语句的值上下文之外,你还能找出哪些值上下文? 53 | 请写一些代码示例去尝试一下 -------------------------------------------------------------------------------- /note/chapter1/09.md: -------------------------------------------------------------------------------- 1 | ## 09.语法面面观:数据类型 (上) 2 | 3 | 4 | ## Rust中的类型 5 | 6 | 1. 基本数据类型 7 | 2. 自定义复合类型 8 | 3. 容器类型 9 | 4. 泛型 10 | 5. 特定类型 11 | 12 | #### 基本数据类型 13 | 14 | ![](./img/09datatype.png) 15 | 16 | 17 | 字符串使用场景->字符串类型 18 | 19 | 1. 字面量 20 | 2. 动态可增长字符串 21 | 3. 从一段字符串中截取的片段 22 | 4. 字符串编码 23 | 5. FFi 中需要转换字符串到 C 或 OS 本地字符串 24 | 6. 遵循特定格式的文件路径 25 | 26 | #### Rust指针类型 27 | 28 | - 原始指针 29 | - NonNull指针 30 | - 函数指针 31 | 32 | #### 引用 33 | 34 | &T 和 &mut T 35 | 36 | #### Never类型 37 | 38 | 代表不可能返回值的计算类型 39 | 40 | 底类型:不包含任何值,但是他可以合一到任何其他类型 41 | 42 | Never类型用 !叹号表示 43 | 44 | #### 复合类型 45 | 46 | 1. 结构体Struct 47 | 2. 枚举体 Enum 48 | 3. 联合体 Union 49 | 50 | 51 | #### 结构体内存布局 52 | 53 | 会进行内存重排 54 | 55 | [demo](..src/demo/09.rs) 56 | 57 | [官方文档](https://doc.rust-lang.org/std/mem/fn.size_of.html) 58 | 59 | 60 | #### 泛型 61 | 62 | 静态分发和turbefish 63 | 64 | [demo](../src/demo/09_turbefish.rs) 65 | 66 | 67 | #### 特定类型 68 | 69 | 有特殊用途的类型 70 | 71 | 1. PhantomData 幻影类型 72 | 2. Pin 固定类型 73 | 74 | ## 作业 75 | 76 | 1. 请自行阅读标准库文档,按课程中的类型分类,自己梳理一遍类型。 77 | 相信你能发现更细节的内容 78 | 79 | 80 | -------------------------------------------------------------------------------- /note/chapter1/10.md: -------------------------------------------------------------------------------- 1 | ## 10.语法面面观:数据类型 (下) 2 | 3 | 4 | ## 什么是trait 5 | 6 | trait 是行为的抽象 7 | 8 | 孤儿规则:trait或者类型,必须有一个在本地定义 9 | 10 | train是一种特设的多态,用于函数重载 11 | 12 | 13 | ## trait 掌控类型行为逻辑 14 | 15 | fn main() { 16 | let a= 42; 17 | let b = a; 18 | a; // 变量a没有被Move,因为实现了Copy trait 19 | } 20 | 21 | 仿射类型:类型系统中用于标识内存等资源,最多只能被使用一次 22 | 23 | -------------------------------------------------------------------------------- /note/chapter1/11.md: -------------------------------------------------------------------------------- 1 | ## 11.语法面面观:函数与闭包(上) 2 | 3 | ## 常规函数 4 | 5 | 1. 都拥有显式的类型签名 6 | 2. 三种类型:自由函数,关联函数和方法 7 | 3. 函数自身也是一种类型 8 | 9 | ## 函数指针 10 | 11 | 1. 函数项类型可以通过显式指定函数类型转换为一个函数指针类型 12 | 2. 在写代码的时候,尽可能地去使用 函数项类型,不到万不得已不 13 | 要使用函数指针类型,这样有助于享受零大小类型的优化 14 | 15 | ## 闭包 16 | 17 | [demo](../src/demo/11.rs) -------------------------------------------------------------------------------- /note/chapter1/12.md: -------------------------------------------------------------------------------- 1 | ## 12.语法面面观:函数与闭包(中) 2 | 3 | ## Rust闭包的实现原理 4 | 5 | 1. 未捕捉环境变量 6 | 2. 捕捉而且修改环境变量 7 | 3. 捕捉但未修改环境变量 8 | 9 | ## 闭包的分类 10 | 11 | 1. 如果没有任何捕获变量,则实现 FnOnce。 12 | 2. 如果有捕获变量,并且会对捕获变量进行修改,则实现 FnMut 。 13 | 3. 如果有捕获变量,并且不会对捕获变量进行修改,则实现 Fn。 -------------------------------------------------------------------------------- /note/chapter1/13.md: -------------------------------------------------------------------------------- 1 | ## 13.Rust 语法面面观:函数与闭包(下) 2 | 3 | ## 逃逸闭包与非逃逸闭包 4 | 5 | 逃逸闭包: 能为函数返回,不在函数调用过程中被销毁的闭包 6 | 7 | 8 | ## 闭包自身实现哪些trait 9 | 10 | 1. Sized 默认实现 11 | 2. Copy/ Clone 取决于环境变量 12 | 3. Sync / Send 取决于环境变量 13 | 14 | 15 | -------------------------------------------------------------------------------- /note/chapter1/14.md: -------------------------------------------------------------------------------- 1 | ## 14.Rust 语法面面观:模式匹配 2 | 3 | 4 | ## 支持的位置 5 | 6 | 1. let 声明 7 | 2. 函数和闭包参数 8 | 3. match 表达式 9 | 4. if let 表达式 10 | 5. while let 表达式 11 | 6. for 表达式 12 | 13 | ## 支持的类型 14 | 15 | 1. 不可辨驳的类型 完全匹配 16 | 2. 可辩驳的类型 17 | 18 | -------------------------------------------------------------------------------- /note/chapter1/15.md: -------------------------------------------------------------------------------- 1 | ## 15.Rust 语法面面观:智能指针(上) 2 | 3 | 4 | ## 什么是智能指针 5 | 6 | 内存管理机制,来自于C++的RAII 7 | 8 | trait决定了类型的行为 9 | 1. Deref trait 10 | 2. Drop trait 11 | 12 | -------------------------------------------------------------------------------- /note/chapter1/16.md: -------------------------------------------------------------------------------- 1 | ## 16.语法面面观:智能指针(下) 2 | 3 | 4 | ## 智能指针的用处 5 | 6 | 1. 自动解引用 7 | 2. 自动化管理内存 8 | 9 | ## 标准库的智能指针 10 | 11 | 1. Box 12 | 2. Vec 和String 13 | 3. Rc 和 Arc 14 | 4. HashMap 15 | 16 | 17 | -------------------------------------------------------------------------------- /note/chapter1/17.md: -------------------------------------------------------------------------------- 1 | ## 17.语法面面观:字符与字符串(上) 2 | 3 | 4 | ## 字符 5 | 6 | Unicode标量值 u32类型 4个字节 7 | 8 | 9 | ## 字符串 10 | 11 | UTF-8字符序列 12 | 13 | str 和 String两大常用的字符串类型 14 | 15 | 其他字符串分类,与其他语言,或者操作系统交互时使用 16 | 17 | Cstr/CString 18 | OsStr/OsString 19 | Path/PathBuf 20 | 21 | -------------------------------------------------------------------------------- /note/chapter1/18.md: -------------------------------------------------------------------------------- 1 | # 18 Rust 语法面面观:字符与字符串(下) 2 | 3 | 4 | ## 查看标准库的步骤 5 | 6 | https://doc.rust-lang.org/std/primitive.str.html 7 | 8 | 9 | 1. 查看类型自身的介绍 10 | 2. 查看类型自身实现的方法 11 | 3. 查看类型实现的 trait -------------------------------------------------------------------------------- /note/chapter1/19.md: -------------------------------------------------------------------------------- 1 | ## 19. Rust 语法面面观:集合容器(上) 2 | 3 | ## 集合容器 4 | 5 | 1. Vec,动态可增长数组 6 | 2. VecDeque,基于环形缓冲区的先进先出双端队列 7 | 3. LinkedList,非侵入式双向链表实现 8 | 4. BinaryHeap,二叉堆实现,可用做优先队列 9 | 5. HashMap / BTreeMap 10 | 6. HashSet / BTreeMap -------------------------------------------------------------------------------- /note/chapter1/20.md: -------------------------------------------------------------------------------- 1 | ## 20. Rust 语法面面观:集合容器(下) 2 | 3 | ## 集合容器 4 | 5 | 1. Vec,动态可增长数组 6 | 2. VecDeque,基于环形缓冲区的先进先出双端队列 7 | 3. LinkedList,非侵入式双向链表实现 8 | 4. BinaryHeap,二叉堆实现,可用做优先队列 9 | 5. HashMap / BTreeMap 10 | 6. HashSet / BTreeMap 11 | 12 | 13 | collections文档:https://doc.rust-lang.org/std/collections/index.html 14 | 15 | 16 | ## HashMap 的实现 17 | 18 | 1.hash算法默认实现是:SipHash-1-3 可以抵抗HashDos攻击 19 | 20 | 可替换的hash算法实现: fnv库,性能好 不可抵抗HashDos攻击 21 | 22 | ## GAT 是什么 23 | 24 | https://github.com/rust-lang/rust/issues/44265 25 | https://zhuanlan.zhihu.com/p/113067733 26 | 27 | 28 | -------------------------------------------------------------------------------- /note/chapter1/21.md: -------------------------------------------------------------------------------- 1 | ## 21.Rust 语法面面观:迭代器(上) 2 | 3 | 4 | ## 迭代器模式 5 | 6 | 1.外部迭代器 7 | 2.内部迭代器 8 | 9 | 10 | ## 标准库迭代器 11 | 12 | https://doc.rust-lang.org/std/iter/index.html 13 | 14 | 迭代器的三种类型 15 | 1. iter() 16 | 2. iter_mut() 17 | 3. into_iter() 18 | 19 | -------------------------------------------------------------------------------- /note/chapter1/22.md: -------------------------------------------------------------------------------- 1 | ## 22.Rust 语法面面观:迭代器(下) 2 | 3 | 4 | ## 标准库中的迭代器适配器 5 | 6 | 7 | https://kaisery.github.io/trpl-zh-cn/ch13-02-iterators.html 8 | 9 | ## 标准库中的迭代器消费器 10 | 11 | https://kaisery.github.io/trpl-zh-cn/ch13-02-iterators.html 12 | 13 | 14 | ## 第三方库: Itertools 15 | 16 | https://docs.rs/itertools/0.9.0/itertools/ -------------------------------------------------------------------------------- /note/chapter1/23.md: -------------------------------------------------------------------------------- 1 | ## 23.Rust语法面面观:模块 2 | 3 | 4 | ## 什么是模块 5 | 6 | 一组语法项的集合 7 | 8 | 1. 使用mod关键字定义 9 | 2. 可以定义于单个文件 10 | 3. 定义于多个文件 11 | 12 | 13 | ## 多模块之间的关系 14 | 15 | 同级模块使用 crate 前缀 16 | 父级模块使用 super 前缀 17 | 包外模块之间使用包名 18 | -------------------------------------------------------------------------------- /note/chapter1/24.md: -------------------------------------------------------------------------------- 1 | ## 24.Rust语法面面观:Cargo包管理器(上) 2 | 3 | 4 | ## 什么是包 5 | 6 | 1. Package 和 crate 都是指 包 7 | 2. Package 是概念层的包,包含了单个或多个 crate 8 | 3. crate 是实际编译单元 9 | 10 | 11 | ## 什么是Cargo 12 | 13 | 1. 引入了 Cargo.toml 和 Cargo.lock 元数据文件 14 | 2. 提取并构建各种依赖包 15 | 3. 使用正确的参数来调用 rustc 或 其他工具构建包 16 | 4. 引入了约定,使得使用 Rust 包更加容易 17 | 18 | ## 基本包结构 19 | 20 | ![](./img/24cargo.png) 21 | 22 | -------------------------------------------------------------------------------- /note/chapter1/25.md: -------------------------------------------------------------------------------- 1 | ## 25.Rust语法面面观:Cargo包管理器(下) 2 | 3 | 4 | ## Cargo命令 5 | 1. cargo check, 对当前crate及其依赖项进行静态检查,不构建 6 | 2. cargo build,执行静态检查且生成编译文件 7 | 3. cargo run,检查 + 构建 + 执行 8 | 4. cargo clean,清除 cargo 构建文件 9 | 5. cargo doc,生成 文档 10 | 11 | 12 | ## Cargo 常用工具 13 | 14 | 1. cargo fix 15 | 2. cargo add 16 | 3. cargo audit 17 | 4. cargo clippy 18 | 5. cargo fmt 19 | 6. cargo expand 20 | 21 | ## 资源 22 | 23 | 1. [cargo book](https://doc.rust-lang.org/cargo/) 24 | [cargo book 翻译版本](https://github.com/chinanf-boy/cargo-book-zh/blob/master/readme.md) 25 | -------------------------------------------------------------------------------- /note/chapter1/26.md: -------------------------------------------------------------------------------- 1 | ## 26.语法面面观:实际项目的组织结构(上) 2 | 3 | 4 | ## 开源项目的代码组织结构 5 | 6 | #### [Rust](https://github.com/rust-lang/rust) 7 | 8 | 1. 根据功能业务来组织,不断迭代 9 | 2. 目前分为compiler,src和library三大类 10 | 3. 通过一个[workspace](https://github.com/rust-lang/rust/blob/master/Cargo.toml)来管理整个项目 11 | 4. 子项目示例: [std](https://github.com/rust-lang/rust/blob/master/library/std/Cargo.toml) 12 | 13 | #### [wasmtime](https://github.com/bytecodealliance/wasmtime) 14 | 15 | 1. 它是一个命令行工具,组织的形式也是通过自身业务功能来分割的 16 | 2. wasmtime/cranelft/umbrella示例: [src](https://github.com/bytecodealliance/wasmtime/blob/main/cranelift/umbrella/src/lib.rs) -------------------------------------------------------------------------------- /note/chapter1/27.md: -------------------------------------------------------------------------------- 1 | ## 27.语法面面观:实际项目的组织结构(下) 2 | 3 | #### [futures-rs](https://github.com/rust-lang/futures-rs) 4 | 5 | 1. 按功能来区分,都是独立的create 6 | 7 | #### [async-std](https://github.com/async-rs/async-std) 8 | 9 | 1. 它是一个库,提供一个[lib.rs](https://github.com/async-rs/async-std/blob/master/src/lib.rs) 10 | 2. 组织形式比较正规库的结构 11 | 12 | #### [tokio](https://github.com/tokio-rs/tokio) 13 | 14 | 1. 提供的工具和主库是并行的,独立组织 15 | 2. 主库是标准库结构 16 | 17 | #### [Rocket](https://github.com/SergioBenitez/Rocket) 18 | 19 | 1. 整个框架核心在[core](https://github.com/SergioBenitez/Rocket/tree/master/core)里面,里面再分为三个模块codegen,http,lib 20 | 21 | 22 | #### [actix-web](https://github.com/actix/actix-web) 23 | 24 | 1. 和Rocket类似,但是并不是core中,而且直接独立为几个大的模块 25 | 2. 也是通过[workspace](https://github.com/actix/actix-web/blob/master/Cargo.toml)来管理独立的模块 26 | 27 | #### [tikv](https://github.com/tikv/tikv) 28 | 29 | 1. 和Rust官方库类似,按照基本业务来组织 30 | 31 | 32 | ## 总结 33 | 34 | 根据自身业务属性去组织 35 | 36 | 1. Cranelift 的 umbrella 结构 和 Futures-rs 的相似 37 | 38 | 2. async-std 和 tokio 的相似 39 | 40 | 3. Rocket 和 Actix-web 的相似 41 | 42 | 4. TiKV 和 Rust 的相似 43 | 44 | ## 作业 45 | 46 | 自己再查看一遍这八个开源项目的组织结构,总结有 47 | 什么特点? -------------------------------------------------------------------------------- /note/chapter1/28.md: -------------------------------------------------------------------------------- 1 | ## 28.语法面面观:定义自己的Crate(上) 2 | 3 | 4 | 5 | ## 创建自己的Crate 6 | 7 | [toml-demo](../src/demo/toml-demo) 项目 8 | 9 | #### Poem框架-配置文件读取 10 | 11 | 1. 读取toml配置文件 12 | 2. 按照不同的Env环境读取配置 13 | 14 | 15 | #### 开发 16 | 17 | 环境: cargo install cargo-edit 18 | 19 | 20 | #### 具体流程 21 | 22 | 定义一个类去读取一个配置文件,这里涉及到几种模式,几种模式的配置字段不一样 23 | 24 | 25 | -------------------------------------------------------------------------------- /note/chapter1/29.md: -------------------------------------------------------------------------------- 1 | ## 29.语法面面观:定义自己的Crate(中) 2 | 3 | ## 重构 4 | 5 | 6 | [toml-demo-refactor](../src/demo/toml-demo-refactor) 项目 7 | 8 | 9 | #### 思路 10 | 11 | 1. 分模块,把依赖的模块抽出来作为一个lib 12 | 13 | 2. 分文件,让项目的文件结构更简洁 14 | 15 | -------------------------------------------------------------------------------- /note/chapter1/30.md: -------------------------------------------------------------------------------- 1 | ## 30.语法面面观:定义自己的Crate(下) 2 | 3 | ## 最佳实践 4 | 5 | 1. 设置一个默认的配置 6 | 2. 公用模块放到lib下 7 | 3. 带前缀的代码可读性更好 8 | 9 | 链接: https://tarquin-the-brave.github.io/blog/posts/rust_use_statements/ 10 | 11 | -------------------------------------------------------------------------------- /note/chapter1/31.md: -------------------------------------------------------------------------------- 1 | ## 31. 作业&第二章预告 2 | 3 | 4 | ## 作业 5 | 6 | 1. 思维导图梳理知识 7 | 8 | 9 | 10 | ## 第二章 11 | 12 | 1. 掌握所有权语义 13 | 2. 领略Rust的工程能力 14 | 3. 掌握元编程能力 15 | 4. 正确认识 Unsafe Rust 16 | 17 | 18 | -------------------------------------------------------------------------------- /note/chapter1/img/08copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter1/img/08copy.png -------------------------------------------------------------------------------- /note/chapter1/img/08move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter1/img/08move.png -------------------------------------------------------------------------------- /note/chapter1/img/09datatype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter1/img/09datatype.png -------------------------------------------------------------------------------- /note/chapter1/img/24cargo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter1/img/24cargo.png -------------------------------------------------------------------------------- /note/chapter2/32.md: -------------------------------------------------------------------------------- 1 | ## 32. Rust 语言架构 2 | 3 | 4 | ## Rust语言架构 5 | 6 | - 安全抽象 7 | - 范式抽象 8 | - 类型系统 9 | - 资源管理 10 | 11 | 12 | ## Rust语言核心概念 13 | 14 | 1. 掌握所有权语义 15 | 2. 领略Rust的工程能力 16 | 3. 掌握元编程能力 (提供了强大的DSL能力) 17 | 4. 正确认识 Unsafe Rust 18 | 19 | 20 | 21 | ## 图解Rust语言核心概念 22 | 23 | ![](./img/32.png) 24 | 25 | 26 | 27 | 我的重点: 安全管理和安全边界 -------------------------------------------------------------------------------- /note/chapter2/33.md: -------------------------------------------------------------------------------- 1 | ## 33.所有权:内存管理基础知识 2 | 3 | 4 | ## 要解决的问题 5 | 6 | 最主要的就是C/C++很多的安全问题,包括内存安全问题和悬垂指针等 7 | 8 | 内存安全问题包括: 9 | - double free 10 | - invalid free 11 | - 使用未初始化的内存 12 | - 缓冲区溢出 13 | - 解引用空指针 14 | 15 | 16 | 悬垂指针包括 use-after-free 17 | 18 | 19 | ## 怎么解决 20 | 21 | - 无GC,达到性能要求 22 | - 安全抽象: 主要是所有权机制 23 | 24 | 25 | 26 | ## 所有权机制 27 | 28 | 主要是保证空间内存安全和时间内存安全 29 | 30 | - 保证空间内存安全--> 消灭缓冲区溢出 31 | - 保证时间内存安全--> 消灭悬垂指针 32 | 33 | #### 措施 34 | 35 | - 所有权语义,主要是编译期静态类型检查 (这是Rust的难点) 36 | - 自动化内存管理: 确定性析构 37 | 38 | 39 | 40 | ## 图解内存管理 41 | 42 | ![](./img/33.md) 43 | 44 | -------------------------------------------------------------------------------- /note/chapter2/34.md: -------------------------------------------------------------------------------- 1 | ## 34.所有权:安全管理之内存安全 2 | 3 | 4 | ## 语义模型 5 | 6 | ![](./img/34-1.png) 7 | 8 | 比如: let answer = "42" 9 | 10 | 变量 answer 就有了owner 和 引用,也有了作用域和数据 11 | 12 | 13 | ## 类型系统之仿射类型 14 | 15 | 资源 最多只能被消耗一次 16 | 17 | 所以存在 Move 和Copy 语义 18 | 19 | - Move 资源被消耗一次 默认为Move语义 20 | - Copy 资源复制一次之后,进行消耗 要使用需要定义Copy trait 21 | 22 | 23 | ## 内存管理 24 | 25 | 1. 默认存储数据在栈上 26 | 2. 利用栈来自动管理堆内存(栈的变量被清空,那堆的内容也会被清空) 27 | 28 | 29 | ## 借用 30 | 31 | 1. 借用可以当成一个安全的指针 32 | 2. 引用是指向一个有效的数据,如果数据无效了,引用也失效了。 33 | 34 | 35 | ## 共享 36 | 37 | 1. 实现clone traint ,所有权共享 38 | 2. 实现方式:深拷贝和引用计数 39 | 40 | -------------------------------------------------------------------------------- /note/chapter2/35.md: -------------------------------------------------------------------------------- 1 | ## 35.所有权:Copy语义和Copy trait 2 | 3 | -------------------------------------------------------------------------------- /note/chapter2/img/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter2/img/32.png -------------------------------------------------------------------------------- /note/chapter2/img/33.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter2/img/33.png -------------------------------------------------------------------------------- /note/chapter2/img/34-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xxg1413/inviting-rust-note/22f09d6fb3b64b6d6db2d317ce37423669d48f18/note/chapter2/img/34-1.png -------------------------------------------------------------------------------- /src/ch01/lexical.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | //! 第一章:Rust语言基础 3 | //! 1.3 语法面面观(上) 4 | //! 5 | //! 包括: 6 | //! 1. Rust 语言版本说明 7 | //! 2. Rust 语法结构 8 | 9 | /** 10 | 11 | # 标识符: 12 | 13 | ```rust 14 | let thinking = "thinking"; 15 | let thinking123_ = "thinking 123"; 16 | 17 | // error: invalid suffix `thinking` for integer literal 18 | // let 321_thinking = "thinking"; 19 | 20 | // ok 21 | let _321_thinking = "thinking"; 22 | 23 | // non-ascii ident 24 | // RFC: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md 25 | // error: unknown start of token: \u{1f914} 26 | // let 🤔 = "thinking "; 27 | ``` 28 | 29 | */ 30 | pub fn ident_show(){ 31 | let thinking = "thinking"; 32 | 33 | // non-ascii ident 34 | // RFC: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md 35 | // error: unknown start of token: \u{1f914} 36 | // let 🤔 = "thinking "; 37 | } 38 | 39 | /** 40 | 41 | # 声明宏示例 42 | 43 | ```rust 44 | macro_rules! calculate { 45 | (eval $e:expr) => {{ 46 | { 47 | let val: usize = $e; // Force types to be integers 48 | println!("{} = {}", stringify!{$e}, val); 49 | } 50 | }}; 51 | } 52 | 53 | fn main() { 54 | calculate! { 55 | eval 1 + 2 // hehehe `eval` is _not_ a Rust keyword! 56 | } 57 | 58 | calculate! { 59 | eval (1 + 2) * (3 / 4) 60 | } 61 | } 62 | ``` 63 | */ 64 | pub fn macro_show(){ 65 | 66 | macro_rules! calculate { 67 | (eval $e:expr) => {{ 68 | { 69 | let val: usize = $e; // Force types to be integers 70 | println!("{} = {}", stringify!{$e}, val); 71 | } 72 | }}; 73 | } 74 | 75 | calculate! { 76 | eval 1 + 2 // hehehe `eval` is _not_ a Rust keyword! 77 | } 78 | 79 | calculate! { 80 | eval (1 + 2) * (3 / 4) 81 | } 82 | 83 | } 84 | 85 | 86 | 87 | /** 88 | 89 | # Path 展示 90 | 91 | ``` 92 | // 模块路径 93 | mod a { 94 | fn foo() {} 95 | 96 | mod b { 97 | mod c { 98 | fn foo() { 99 | super::super::foo(); // call a's foo function 100 | self::super::super::foo(); // call a's foo function 101 | } 102 | } 103 | } 104 | } 105 | 106 | // 方法调用 107 | 108 | struct S; 109 | impl S { 110 | fn f() { println!("S"); } 111 | } 112 | trait T1 { 113 | fn f() { println!("T1 f"); } 114 | } 115 | impl T1 for S {} 116 | trait T2 { 117 | fn f() { println!("T2 f"); } 118 | } 119 | impl T2 for S {} 120 | S::f(); // Calls the inherent impl. 121 | // 完全限定无歧义调用 122 | ::f(); // Calls the T1 trait function. 123 | ::f(); // Calls the T2 trait function. 124 | 125 | 126 | // 泛型函数-turbofish操作符 127 | (0..10).collect::>(); 128 | Vec::::with_capacity(1024); 129 | ``` 130 | 131 | */ 132 | pub fn path_show() { 133 | (0..10).collect::>(); 134 | Vec::::with_capacity(1024); 135 | } 136 | 137 | /** 138 | # 注释示例 139 | pub mod outer_module { 140 | 141 | //! - 模块级文档注释,置于模块头部 142 | //!! - 模块级文档注释,但是和上面注释置于同一行 143 | 144 | //! - 模块级文档注释,但会换行 145 | 146 | /*! - 模块块级文档注释 */ 147 | /*!! - 模块级注释,但是和上面注释置于同一行 */ 148 | 149 | /*! - 模块块级注释,但会换行 */ 150 | 151 | // - 普通行注释 152 | /// - 行级文档注释 ( 必须是 3 个斜杠) 153 | //// - 普通行注释 154 | 155 | /* - 普通块级注释 */ 156 | /** - 块级文档注释 (精确) 2 个星号 */ 157 | /*** - 普通注释 */ 158 | 159 | pub mod inner_module {} 160 | 161 | pub mod nested_comments { 162 | /* Rust 中的注释内/* 可以 /* 嵌入注释 */ */ */ 163 | 164 | // 所有三种块注释都可以相互包含或嵌套 165 | 166 | /* /* */ /** */ /*! */ */ 167 | /*! /* */ /** */ /*! */ */ 168 | /** /* */ /** */ /*! */ */ 169 | pub mod dummy_item {} 170 | } 171 | 172 | pub mod degenerate_cases { 173 | // 空的模块级文档注释 174 | //! 175 | 176 | // 空的模块块级文档注释 177 | /*!*/ 178 | 179 | // 空的行注释 180 | // 181 | 182 | // empty outer line doc 183 | /// 空的行级文档注释 184 | 185 | // 空的块注释 186 | /**/ 187 | 188 | pub mod dummy_item {} 189 | 190 | // 注意,此处不是空的块级文档注释,而只是一个普通的块级注释 191 | /***/ 192 | 193 | } 194 | 195 | /* 196 | 下面这种文档注释是不允许的,因为文档注释下面必须要有语言项,比如方法、函数等 197 | /// Where is my item? 198 | */ 199 | } 200 | 201 | */ 202 | pub mod outer_module { 203 | 204 | //! - 模块级文档注释,置于模块头部 205 | //!! - 模块级文档注释,但是和上面注释置于同一行 206 | 207 | //! - 模块级文档注释,但会换行 208 | 209 | /*! - 模块块级文档注释 */ 210 | /*!! - 模块级注释,但是和上面注释置于同一行 */ 211 | 212 | /*! - 模块块级注释,但会换行 */ 213 | 214 | // - 普通行注释 215 | /// - 行级文档注释 ( 必须是 3 个斜杠) 216 | //// - 普通行注释 217 | 218 | /* - 普通块级注释 */ 219 | /** - 块级文档注释 (精确) 2 个星号 */ 220 | /*** - 普通注释 */ 221 | 222 | pub mod inner_module {} 223 | 224 | /// mod 定义个模块 225 | pub mod nested_comments { 226 | /* Rust 中的注释内/* 可以 /* 嵌入注释 */ */ */ 227 | 228 | // 所有三种块注释都可以相互包含或嵌套 229 | 230 | /* /* */ /** */ /*! */ */ 231 | /*! /* */ /** */ /*! */ */ 232 | /** /* */ /** */ /*! */ */ 233 | pub mod dummy_item {} 234 | } 235 | 236 | pub mod degenerate_cases { 237 | // 空的模块级文档注释 238 | //! 239 | 240 | // 空的模块块级文档注释 241 | /*!*/ 242 | 243 | // 空的行注释 244 | // 245 | 246 | // empty outer line doc 247 | /// 空的行级文档注释 248 | 249 | // 空的块注释 250 | /**/ 251 | 252 | pub mod dummy_item {} 253 | 254 | // 注意,此处不是空的块级文档注释,而只是一个普通的块级注释 255 | /***/ 256 | 257 | } 258 | 259 | /* 260 | 下面这种文档注释是不允许的,因为文档注释下面必须要有语言项,比如方法、函数等 261 | /// Where is my item? 262 | */ 263 | } 264 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /src/ch01/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | //! 第一章:Rust语言基础 3 | //! 4 | 5 | 6 | pub mod lexical; 7 | 8 | /// # Examples 9 | /// 10 | /// Basic usage: 11 | /// 12 | /// ``` 13 | /// println!("第1章:{}", "Rust语言基础"); 14 | /// 15 | /// ``` 16 | pub fn title(){ 17 | println!("第1章:{}", "Rust语言基础"); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /src/demo/06.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | use std::collections::HashMap; 4 | 5 | 6 | fn add_one(i: &mut u32) { 7 | 8 | *i += 1; 9 | } 10 | 11 | 12 | fn plus_one(i:& u32) -> u32 { 13 | let i = i + 1; 14 | i 15 | } 16 | 17 | 18 | fn main() { 19 | 20 | let mut a = 41; 21 | add_one(&mut a); 22 | println!("{:?}", a); 23 | 24 | let mut a = 41; 25 | let b = plus_one(&a); 26 | println!("{:?}",b); 27 | 28 | let mut h = HashMap::new(); 29 | h.insert("anwser", 42); 30 | println!("anwser is {:?}", h["anwser"]); 31 | } -------------------------------------------------------------------------------- /src/demo/09.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] //指定内存布局属性,编译器不会重排结构 2 | 3 | struct A { 4 | a: u8, 5 | b: u32, 6 | c: u16, 7 | } 8 | 9 | fn main() { 10 | println!("{:?}",std::mem::size_of::()); 11 | // 重排: 8 不重排: 12 12 | let v = A {a: 1, b: 2, c: 3}; 13 | 14 | } -------------------------------------------------------------------------------- /src/demo/09_turbefish.rs: -------------------------------------------------------------------------------- 1 | 2 | fn foo(x: T) -> T { 3 | println!("{}", std::any::type_name::()); 4 | return x; 5 | } 6 | 7 | fn main() { 8 | println!("{:?}",foo(1)); //i32 9 | println!("{:?}",foo("1")); 10 | println!("{:?}",foo::(1)); //u32 11 | } -------------------------------------------------------------------------------- /src/demo/10.rs: -------------------------------------------------------------------------------- 1 | struct A; 2 | 3 | impl A{ 4 | fn hello(&self){ 5 | println!("in A"); 6 | } 7 | } 8 | 9 | trait Hello { 10 | fn hello(&self); 11 | } 12 | 13 | impl Hello for A { 14 | fn hello(&self){ 15 | println!("from Hello trait"); 16 | } 17 | } 18 | 19 | fn main() { 20 | 21 | let a = A; 22 | a.hello(); 23 | 24 | ::hello(&a); 25 | 26 | } -------------------------------------------------------------------------------- /src/demo/11.rs: -------------------------------------------------------------------------------- 1 | 2 | fn counter(i: i32) -> impl FnMut(i32) ->i32 { 3 | move |n| n+i 4 | } 5 | 6 | 7 | fn main() { 8 | let mut f = counter(2); 9 | println!("{:?}", f(1)); 10 | } -------------------------------------------------------------------------------- /src/demo/15.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::ops::Deref; 3 | 4 | struct MySmartPointer(T); 5 | 6 | impl MySmartPointer { 7 | fn new(x: T) -> MySmartPointer { 8 | MySmartPointer(x) 9 | } 10 | } 11 | 12 | 13 | impl Deref for MySmartPointer { 14 | type Target = T; 15 | 16 | fn deref(&self) -> &T { 17 | &self.0 18 | } 19 | } 20 | 21 | 22 | fn main() { 23 | 24 | let x: Box = Box::new(42); 25 | let y = *x; 26 | 27 | assert_eq!(y, 42); 28 | 29 | let x = 5; 30 | let y = MySmartPointer::new(x); 31 | 32 | assert_eq!(5, *y); 33 | } -------------------------------------------------------------------------------- /src/demo/22.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | let v: Vec = vec![1,2,3].into_iter().map(|i| i+1).rev().collect(); 4 | println!("{:?}", v); 5 | } -------------------------------------------------------------------------------- /src/demo/35.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused)] 2 | 3 | fn main() { 4 | 5 | let a = 42; 6 | let b = a; 7 | println!("{:?}", a); 8 | 9 | 10 | let a = "42"; 11 | let b = a; 12 | println!("{:?}", a); 13 | 14 | 15 | let a = "42".to_string(); 16 | let b : &str = &a; 17 | 18 | println!("{:?}",b); 19 | 20 | 21 | 22 | let a = "42".to_string(); 23 | let b : &str = &a; 24 | let c = b; 25 | //println!("{:?}",b); //borrowed 26 | println!("{:?}",c); 27 | } -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /target -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "toml-demo" 3 | version = "0.1.0" 4 | authors = ["Jimmy Xiang "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [[bin]] 10 | name = "main" 11 | path = "bin/main.rs" 12 | 13 | [dependencies] 14 | toml = "0.5" 15 | serde = {version="1.0", features=["derive"]} 16 | num_cpus = "1.13.0" 17 | -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/README.md: -------------------------------------------------------------------------------- 1 | ### Usage: 2 | 3 | Development: 4 | 5 | > POEM_ENV=d cargo run 6 | > POEM_ENV=dev cargo run 7 | > POEM_ENV=development cargo run 8 | 9 | Staging: 10 | 11 | > POEM_ENV=s cargo run 12 | > POEM_ENV=stage cargo run 13 | > POEM_ENV=staging cargo run 14 | 15 | Production: 16 | 17 | > POEM_ENV=p cargo run 18 | > POEM_ENV=prod cargo run 19 | > POEM_ENV=production cargo run -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/bin/main.rs: -------------------------------------------------------------------------------- 1 | 2 | use toml_demo; 3 | 4 | fn main() { 5 | 6 | let conf = toml_demo::PoemConfig::read_config(); 7 | println!("{:#?}", conf); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/config/Poem.toml: -------------------------------------------------------------------------------- 1 | [development] 2 | address = "localhost" 3 | port = "8000" 4 | workers = 4 5 | 6 | [development.database] 7 | adapter = "postgresql" 8 | db_name = "blog_development" 9 | pool = 5 10 | 11 | [staging] 12 | address = "0.0.0.0" 13 | port = "9000" 14 | 15 | [staging.database] 16 | adapter = "postgresql" 17 | db_name = "blog_development" 18 | pool = 5 19 | 20 | 21 | [production] 22 | address = "0.0.0.0" 23 | port = "9000" 24 | 25 | [production.database] 26 | adapter = "postgresql" 27 | db_name = "blog_development" 28 | pool = 5 -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/src/conf.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod basic_config; 2 | pub(crate) mod poem_config; 3 | pub(crate) mod error; 4 | 5 | use super::*; 6 | use std::fs::{self,File}; 7 | use std::io::Read; 8 | use std::path::{PathBuf,Path}; 9 | 10 | 11 | use toml; 12 | 13 | pub use self::error::ConfigError; 14 | pub use self::poem_config::PoemConfig; 15 | pub use self::basic_config::BasicConfig; 16 | 17 | use crate::environment::{Environment,Environment::*}; 18 | use std::collections::HashMap; 19 | 20 | const CONFIG_FILENAME: &str = "config/Poem.toml"; 21 | pub type Result = ::std::result::Result; 22 | -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/src/conf/basic_config.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | #[derive(Debug)] 4 | pub struct BasicConfig { 5 | pub environment: super::Environment, 6 | pub address: String, 7 | pub port: u16, 8 | pub database: Option, 9 | pub workers: Option, 10 | pub(crate) config_file_path: Option, 11 | pub(crate) root_path: Option, 12 | } 13 | 14 | impl BasicConfig { 15 | pub fn new(env: super::Environment) -> Self { 16 | Self::default(env) 17 | } 18 | 19 | pub(crate) fn default(env: super::Environment) -> Self { 20 | let default_workers = (num_cpus::get() * 2) as u16; 21 | let default_config = BasicConfig { 22 | environment: Development, 23 | address: "localhost".to_string(), 24 | port: 8000, 25 | database: None, 26 | workers: Some(default_workers), 27 | config_file_path: None, 28 | root_path: None, 29 | }; 30 | 31 | match env { 32 | Development => { 33 | BasicConfig { 34 | environment: Development, 35 | ..default_config 36 | } 37 | } 38 | Staging => { 39 | BasicConfig { 40 | environment: Staging, 41 | ..default_config 42 | } 43 | } 44 | Production => { 45 | BasicConfig { 46 | environment: Production, 47 | ..default_config 48 | } 49 | } 50 | } 51 | } 52 | 53 | pub(crate) fn set_root>(&mut self, path: P) { 54 | self.root_path = Some(path.as_ref().into()); 55 | } 56 | 57 | pub(crate) fn default_from

(env: super::Environment, path: P) -> super::Result 58 | where P: AsRef 59 | { 60 | let mut config = BasicConfig::default(env); 61 | 62 | let config_file_path = path.as_ref().to_path_buf(); 63 | if let Some(parent) = config_file_path.parent() { 64 | config.set_root(parent); 65 | } else { 66 | let msg = "Configuration files must be rooted in a directory."; 67 | return Err(ConfigError::BadFilePath(config_file_path.clone(), msg)); 68 | } 69 | 70 | config.config_file_path = Some(config_file_path); 71 | Ok(config) 72 | } 73 | } 74 | 75 | impl PartialEq for BasicConfig { 76 | fn eq(&self, other: &BasicConfig) -> bool { 77 | self.address == other.address 78 | && self.port == other.port 79 | && self.workers == other.workers 80 | } 81 | } 82 | 83 | #[derive(Debug)] 84 | pub struct Database { 85 | pub(crate) adapter: String, 86 | pub(crate) db_name: String, 87 | pub(crate) pool: u32, 88 | } -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/src/conf/error.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::*; 3 | use std::error::Error; 4 | use self::ConfigError::*; 5 | 6 | #[derive(Debug)] 7 | pub enum ConfigError { 8 | /// The configuration file was not found. 9 | NotFound, 10 | /// There was an I/O error while reading the configuration file. 11 | IoError, 12 | /// The path at which the configuration file was found was invalid. 13 | BadFilePath(PathBuf, &'static str), 14 | /// An environment specified in `POEM_ENV` is invalid. 15 | BadEnv(String), 16 | /// An environment specified as a table `[environment]` is invalid. 17 | BadEntry(String, PathBuf), 18 | /// A config key was specified with a value of the wrong type. 19 | BadType(String, &'static str, &'static str, Option), 20 | /// There was a TOML parsing error. 21 | ParseError(String, PathBuf, String, Option<(usize, usize)>), 22 | } 23 | 24 | impl Error for ConfigError { 25 | fn description(&self) -> &str { 26 | match *self { 27 | NotFound => "config file was not found", 28 | IoError => "there was an I/O error while reading the config file", 29 | BadFilePath(..) => "the config file path is invalid", 30 | BadEnv(..) => "the environment specified in `ROCKET_ENV` is invalid", 31 | BadEntry(..) => "an environment specified as `[environment]` is invalid", 32 | BadType(..) => "a key was specified with a value of the wrong type", 33 | ParseError(..) => "the config file contains invalid TOML", 34 | } 35 | } 36 | } 37 | 38 | impl fmt::Display for ConfigError { 39 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 40 | match *self { 41 | NotFound => write!(f, "config file was not found"), 42 | IoError => write!(f, "I/O error while reading the config file"), 43 | BadFilePath(ref p, _) => write!(f, "{:?} is not a valid config path", p), 44 | BadEnv(ref e) => write!(f, "{:?} is not a valid `ROCKET_ENV` value", e), 45 | BadEntry(ref e, _) => { 46 | write!(f, "{:?} is not a valid `[environment]` entry", e) 47 | } 48 | BadType(ref n, e, a, _) => { 49 | write!(f, "type mismatch for '{}'. expected {}, found {}", n, e, a) 50 | } 51 | ParseError(..) => write!(f, "the config file contains invalid TOML"), 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/src/conf/poem_config.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::*; 3 | 4 | #[doc(hidden)] 5 | #[derive(Debug, PartialEq)] 6 | pub struct PoemConfig { 7 | pub active_env: Environment, 8 | config: HashMap, 9 | } 10 | 11 | impl PoemConfig { 12 | 13 | pub fn read_config() -> super::Result { 14 | let file = PoemConfig::find()?; 15 | 16 | // Try to open the config file for reading. 17 | let mut handle = File::open(&file).map_err(|_| ConfigError::IoError)?; 18 | 19 | let mut contents = String::new(); 20 | handle.read_to_string(&mut contents).map_err(|_| ConfigError::IoError)?; 21 | 22 | PoemConfig::parse(contents, &file) 23 | } 24 | 25 | fn find() -> super::Result { 26 | let cwd = env::current_dir().map_err(|_| ConfigError::NotFound)?; 27 | let mut current = cwd.as_path(); 28 | 29 | loop { 30 | let manifest = current.join(super::CONFIG_FILENAME); 31 | if fs::metadata(&manifest).is_ok() { 32 | return Ok(manifest) 33 | } 34 | 35 | match current.parent() { 36 | Some(p) => current = p, 37 | None => break, 38 | } 39 | } 40 | 41 | Err(ConfigError::NotFound) 42 | } 43 | 44 | fn get_mut(&mut self, env: Environment) -> &mut BasicConfig { 45 | match self.config.get_mut(&env) { 46 | Some(config) => config, 47 | None => panic!("set(): {} config is missing.", env), 48 | } 49 | } 50 | 51 | pub fn active_default_from(filename: Option<&Path>) -> super::Result { 52 | let mut defaults = HashMap::new(); 53 | if let Some(path) = filename { 54 | defaults.insert(Development, BasicConfig::default_from(Development, &path)?); 55 | defaults.insert(Staging, BasicConfig::default_from(Staging, &path)?); 56 | defaults.insert(Production, BasicConfig::default_from(Production, &path)?); 57 | } else { 58 | defaults.insert(Development, BasicConfig::default(Development)); 59 | defaults.insert(Staging, BasicConfig::default(Staging)); 60 | defaults.insert(Production, BasicConfig::default(Production)); 61 | } 62 | 63 | let mut config = PoemConfig { 64 | active_env: Environment::active()?, 65 | config: defaults, 66 | }; 67 | 68 | Ok(config) 69 | } 70 | 71 | pub fn active() -> super::Result { 72 | Ok(BasicConfig::new(Environment::active()?)) 73 | } 74 | 75 | fn parse>(src: String, filename: P) -> super::Result { 76 | let path = filename.as_ref().to_path_buf(); 77 | let table = match src.parse::() { 78 | Ok(toml::Value::Table(table)) => table, 79 | Ok(value) => { 80 | let err = format!("expected a table, found {}", value.type_str()); 81 | return Err(ConfigError::ParseError(src, path, err, Some((1, 1)))); 82 | } 83 | Err(e) => return Err(ConfigError::ParseError(src, path, e.to_string(), e.line_col())) 84 | }; 85 | 86 | // Create a config with the defaults; set the env to the active one. 87 | let mut config = PoemConfig::active_default_from(Some(filename.as_ref()))?; 88 | 89 | 90 | // Parse the values from the TOML file. 91 | for (entry, value) in table { 92 | // Each environment must be a table. 93 | let kv_pairs = match value.as_table() { 94 | Some(table) => table, 95 | None => return Err(ConfigError::BadType( 96 | entry, "a table", value.type_str(), Some(path.clone()) 97 | )) 98 | }; 99 | 100 | } 101 | 102 | Ok(config) 103 | } 104 | 105 | } -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/src/environment.rs: -------------------------------------------------------------------------------- 1 | 2 | use super::*; 3 | use std::str::FromStr; 4 | 5 | use crate::conf::ConfigError; 6 | use self::Environment::*; 7 | 8 | pub const CONFIG_ENV: &str = "POEM_ENV"; 9 | 10 | #[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] 11 | pub enum Environment { 12 | /// The development environment. for Debug mode. 13 | Development, 14 | /// The staging environment. for Debug mode. 15 | Staging, 16 | /// The production environment. for Release mode. 17 | Production, 18 | } 19 | 20 | impl Environment { 21 | /// List of all of the possible environments. 22 | pub(crate) const ALL: [Environment; 3] = [Development, Staging, Production]; 23 | 24 | /// String of all valid environments. 25 | pub(crate) const VALID: &'static str = "development, staging, production"; 26 | 27 | pub fn active() -> Result { 28 | match env::var(CONFIG_ENV) { 29 | Ok(s) => s.parse().map_err(|_| ConfigError::BadEnv(s)), 30 | // for Debug mode 31 | #[cfg(debug_assertions)] 32 | _ => Ok(Development), 33 | // for Release mode 34 | #[cfg(not(debug_assertions))] 35 | _ => Ok(Production), 36 | } 37 | } 38 | 39 | #[inline] 40 | pub fn is_dev(self) -> bool { 41 | self == Development 42 | } 43 | 44 | #[inline] 45 | pub fn is_stage(self) -> bool { 46 | self == Staging 47 | } 48 | 49 | #[inline] 50 | pub fn is_prod(self) -> bool { 51 | self == Production 52 | } 53 | } 54 | 55 | impl FromStr for Environment { 56 | type Err = (); 57 | 58 | /// Parsing a production environment: 59 | /// 60 | /// ```rust 61 | /// let env = "p".parse::(); 62 | /// assert_eq!(env.unwrap(), Environment::Production); 63 | /// 64 | /// let env = "prod".parse::(); 65 | /// assert_eq!(env.unwrap(), Environment::Production); 66 | /// ``` 67 | fn from_str(s: &str) -> Result { 68 | let env = match s { 69 | "d" | "dev" | "devel" | "development" => Development, 70 | "s" | "stage" | "staging" => Staging, 71 | "p" | "prod" | "production" => Production, 72 | _ => return Err(()), 73 | }; 74 | 75 | Ok(env) 76 | } 77 | } 78 | 79 | impl fmt::Display for Environment { 80 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 81 | match *self { 82 | Development => write!(f, "development"), 83 | Staging => write!(f, "staging"), 84 | Production => write!(f, "production"), 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/demo/toml-demo-refactor/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use std::fmt; 4 | use std::env; 5 | 6 | mod environment; 7 | mod conf; 8 | 9 | pub use conf::PoemConfig; -------------------------------------------------------------------------------- /src/demo/toml-demo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "toml-demo" 3 | version = "0.1.0" 4 | authors = ["Jimmy Xiang "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | num_cpus = "1.13.0" 11 | serde = "1.0.117" 12 | toml = "0.5.7" 13 | -------------------------------------------------------------------------------- /src/demo/toml-demo/conf/Poem.toml: -------------------------------------------------------------------------------- 1 | [development] 2 | address = "localhost" 3 | port = "8000" 4 | workers = 4 5 | 6 | [development.database] 7 | adapter = "postgresql" 8 | db_name = "blog_development" 9 | pool = 5 10 | 11 | 12 | [staging] 13 | address = "0.0.0.0" 14 | port = "9000" 15 | 16 | [staging.database] 17 | adapter = "postgresql" 18 | db_name = "blog_staging" 19 | pool = 5 20 | 21 | [production] 22 | address="0.0.0.0" 23 | port = "9000" 24 | 25 | [production.database] 26 | adapter = "postgresql" 27 | db_name = "blog_production" 28 | pool = 5 29 | 30 | -------------------------------------------------------------------------------- /src/demo/toml-demo/src/conf.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use serde::Deserialize; 3 | use toml::map::Map; 4 | use std::fs::{self,File}; 5 | use std::io::Read; 6 | use crate::error::{ConfigError}; 7 | use crate::environment::{Environment,Environment::*}; 8 | use std::path::{PathBuf,Path}; 9 | use std::collections::HashMap; 10 | pub use toml::value::{Array, Table, Value, Datetime}; 11 | 12 | use std::env; 13 | 14 | const CONFIG_FILENAME: &str = "conf/Poem.toml"; 15 | pub type Result = ::std::result::Result; 16 | 17 | #[derive(Debug)] 18 | pub struct Database { 19 | pub(crate) adapter: String, 20 | pub(crate) db_name: String, 21 | pub(crate) pool: u32, 22 | } 23 | 24 | #[derive(Debug)] 25 | pub struct BasicConfig { 26 | pub environment: Environment, 27 | pub address: String, 28 | pub port: u16, 29 | pub database: Option, 30 | pub workers: Option, 31 | pub(crate) config_file_path: Option, 32 | pub(crate) root_path: Option, 33 | } 34 | 35 | impl BasicConfig { 36 | 37 | pub fn new(env: Environment) -> Self { 38 | Self::default(env) 39 | } 40 | 41 | pub(crate) fn default(env: Environment) -> Self { 42 | let default_workers = (num_cpus::get() * 2) as u16; 43 | 44 | match env { 45 | Development => { 46 | BasicConfig { 47 | environment: Development, 48 | address: "localhost".to_string(), 49 | port: 8000, 50 | database: None, 51 | workers: Some(default_workers), 52 | config_file_path: None, 53 | root_path: None, 54 | } 55 | } 56 | Staging => { 57 | BasicConfig { 58 | environment: Staging, 59 | address: "0.0.0.0".to_string(), 60 | port: 8000, 61 | database: None, 62 | workers: Some(default_workers), 63 | config_file_path: None, 64 | root_path: None, 65 | } 66 | } 67 | Production => { 68 | BasicConfig { 69 | environment: Production, 70 | address: "0.0.0.0".to_string(), 71 | port: 8000, 72 | database: None, 73 | workers: Some(default_workers), 74 | config_file_path: None, 75 | root_path: None, 76 | } 77 | } 78 | } 79 | } 80 | 81 | pub fn set_root>(&mut self, path: P) { 82 | self.root_path = Some(path.as_ref().into()); 83 | } 84 | 85 | fn default_from

(env: Environment, path: P) -> Result 86 | where P: AsRef 87 | { 88 | let mut config = BasicConfig::default(env); 89 | 90 | let config_file_path = path.as_ref().to_path_buf(); 91 | if let Some(parent) = config_file_path.parent() { 92 | config.set_root(parent); 93 | } else { 94 | let msg = "Configuration files must be rooted in a directory."; 95 | return Err(ConfigError::BadFilePath(config_file_path.clone(), msg)); 96 | } 97 | 98 | config.config_file_path = Some(config_file_path); 99 | Ok(config) 100 | } 101 | 102 | } 103 | 104 | impl PartialEq for BasicConfig { 105 | fn eq(&self, other: &BasicConfig) -> bool { 106 | self.address == other.address 107 | && self.port == other.port 108 | && self.workers == other.workers 109 | } 110 | } 111 | 112 | 113 | 114 | #[doc(hidden)] 115 | #[derive(Debug, PartialEq)] 116 | pub struct PoemConfig { 117 | pub active_env: Environment, 118 | config: HashMap, 119 | } 120 | 121 | impl PoemConfig { 122 | 123 | pub fn read_config() -> Result { 124 | let file = PoemConfig::find()?; 125 | 126 | // Try to open the config file for reading. 127 | let mut handle = File::open(&file).map_err(|_| ConfigError::IoError)?; 128 | 129 | let mut contents = String::new(); 130 | handle.read_to_string(&mut contents).map_err(|_| ConfigError::IoError)?; 131 | 132 | PoemConfig::parse(contents, &file) 133 | } 134 | 135 | fn find() -> Result { 136 | let cwd = env::current_dir().map_err(|_| ConfigError::NotFound)?; 137 | let mut current = cwd.as_path(); 138 | 139 | loop { 140 | let manifest = current.join(CONFIG_FILENAME); 141 | if fs::metadata(&manifest).is_ok() { 142 | return Ok(manifest) 143 | } 144 | 145 | match current.parent() { 146 | Some(p) => current = p, 147 | None => break, 148 | } 149 | } 150 | 151 | Err(ConfigError::NotFound) 152 | } 153 | 154 | fn get_mut(&mut self, env: Environment) -> &mut BasicConfig { 155 | match self.config.get_mut(&env) { 156 | Some(config) => config, 157 | None => panic!("set(): {} config is missing.", env), 158 | } 159 | } 160 | 161 | pub fn active_default_from(filename: Option<&Path>) -> Result { 162 | let mut defaults = HashMap::new(); 163 | if let Some(path) = filename { 164 | defaults.insert(Development, BasicConfig::default_from(Development, &path)?); 165 | defaults.insert(Staging, BasicConfig::default_from(Staging, &path)?); 166 | defaults.insert(Production, BasicConfig::default_from(Production, &path)?); 167 | } else { 168 | defaults.insert(Development, BasicConfig::default(Development)); 169 | defaults.insert(Staging, BasicConfig::default(Staging)); 170 | defaults.insert(Production, BasicConfig::default(Production)); 171 | } 172 | 173 | let mut config = PoemConfig { 174 | active_env: Environment::active()?, 175 | config: defaults, 176 | }; 177 | 178 | Ok(config) 179 | } 180 | 181 | pub fn active() -> Result { 182 | Ok(BasicConfig::new(Environment::active()?)) 183 | } 184 | 185 | fn parse>(src: String, filename: P) -> Result { 186 | let path = filename.as_ref().to_path_buf(); 187 | let table = match src.parse::() { 188 | Ok(toml::Value::Table(table)) => table, 189 | Ok(value) => { 190 | let err = format!("expected a table, found {}", value.type_str()); 191 | return Err(ConfigError::ParseError(src, path, err, Some((1, 1)))); 192 | } 193 | Err(e) => return Err(ConfigError::ParseError(src, path, e.to_string(), e.line_col())) 194 | }; 195 | 196 | // Create a config with the defaults; set the env to the active one. 197 | let mut config = PoemConfig::active_default_from(Some(filename.as_ref()))?; 198 | 199 | 200 | // Parse the values from the TOML file. 201 | for (entry, value) in table { 202 | // Each environment must be a table. 203 | let kv_pairs = match value.as_table() { 204 | Some(table) => table, 205 | None => return Err(ConfigError::BadType( 206 | entry, "a table", value.type_str(), Some(path.clone()) 207 | )) 208 | }; 209 | 210 | } 211 | 212 | Ok(config) 213 | } 214 | 215 | } -------------------------------------------------------------------------------- /src/demo/toml-demo/src/environment.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::str::FromStr; 3 | use std::env; 4 | 5 | use crate::error::ConfigError; 6 | use self::Environment::*; 7 | 8 | pub const CONFIG_ENV: &str = "POEM_ENV"; 9 | 10 | #[derive(Hash, PartialEq, Eq, Debug, Clone, Copy)] 11 | pub enum Environment { 12 | /// The development environment. for Debug mode. 13 | Development, 14 | /// The staging environment. for Debug mode. 15 | Staging, 16 | /// The production environment. for Release mode. 17 | Production, 18 | } 19 | 20 | impl Environment { 21 | /// List of all of the possible environments. 22 | pub(crate) const ALL: [Environment; 3] = [Development, Staging, Production]; 23 | 24 | /// String of all valid environments. 25 | pub(crate) const VALID: &'static str = "development, staging, production"; 26 | 27 | pub fn active() -> Result { 28 | match env::var(CONFIG_ENV) { 29 | Ok(s) => s.parse().map_err(|_| ConfigError::BadEnv(s)), 30 | // for Debug mode 31 | #[cfg(debug_assertions)] 32 | _ => Ok(Development), 33 | // for Release mode 34 | #[cfg(not(debug_assertions))] 35 | _ => Ok(Production), 36 | } 37 | } 38 | 39 | #[inline] 40 | pub fn is_dev(self) -> bool { 41 | self == Development 42 | } 43 | 44 | #[inline] 45 | pub fn is_stage(self) -> bool { 46 | self == Staging 47 | } 48 | 49 | #[inline] 50 | pub fn is_prod(self) -> bool { 51 | self == Production 52 | } 53 | } 54 | 55 | impl FromStr for Environment { 56 | type Err = (); 57 | 58 | /// Parsing a production environment: 59 | /// 60 | /// ```rust 61 | /// let env = "p".parse::(); 62 | /// assert_eq!(env.unwrap(), Environment::Production); 63 | /// 64 | /// let env = "prod".parse::(); 65 | /// assert_eq!(env.unwrap(), Environment::Production); 66 | /// ``` 67 | fn from_str(s: &str) -> Result { 68 | let env = match s { 69 | "d" | "dev" | "devel" | "development" => Development, 70 | "s" | "stage" | "staging" => Staging, 71 | "p" | "prod" | "production" => Production, 72 | _ => return Err(()), 73 | }; 74 | 75 | Ok(env) 76 | } 77 | } 78 | 79 | impl fmt::Display for Environment { 80 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 81 | match *self { 82 | Development => write!(f, "development"), 83 | Staging => write!(f, "staging"), 84 | Production => write!(f, "production"), 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/demo/toml-demo/src/error.rs: -------------------------------------------------------------------------------- 1 | use self::ConfigError::*; 2 | use std::{io, fmt}; 3 | use std::path::{Path, PathBuf}; 4 | use std::error::Error; 5 | 6 | 7 | use self::ConfigError::*; 8 | 9 | 10 | //错误定义 11 | 12 | #[derive(Debug)] 13 | pub enum ConfigError { 14 | 15 | NotFound, 16 | IoError, 17 | BadFilePath(PathBuf,&'static str), 18 | BadEnv(String), 19 | BadEntry(String, PathBuf), 20 | BadType(String, &'static str, &'static str, Option), 21 | ParseError(String,PathBuf,String,Option<(usize,usize)>), 22 | 23 | } 24 | 25 | 26 | impl Error for ConfigError { 27 | 28 | fn description(&self) -> &str { 29 | match *self { 30 | NotFound => "config file not found", 31 | IoError => "I/O error", 32 | BadFilePath(..) => "file path is invalid", 33 | BadEnv(..) => "bad env", 34 | BadEntry(..) => "bad entry", 35 | BadType(..) => "bad type", 36 | ParseError(..) => "parse error", 37 | } 38 | } 39 | } 40 | 41 | 42 | impl fmt::Display for ConfigError { 43 | 44 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 | match *self { 46 | NotFound => write!(f, "config not found"), 47 | IoError => write!(f,"IoError"), 48 | BadFilePath(ref p, _) => write!(f,"{:?}", p), 49 | BadEnv(ref e) => write!(f,"{:?}", e), 50 | BadEntry(ref e, _) => write!(f,"{:?}", e), 51 | BadType(ref n,e,a, _) => write!(f,"{} {} {}", n,e,a), 52 | ParseError(..) => write!(f,"parseError") 53 | 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/demo/toml-demo/src/main.rs: -------------------------------------------------------------------------------- 1 | mod environment; 2 | mod error; 3 | mod conf; 4 | 5 | 6 | fn main() { 7 | let conf = conf::PoemConfig::read_config(); 8 | println!("{:#?}", conf); 9 | } 10 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | #![doc( 3 | html_playground_url = "https://play.rust-lang.org/", 4 | test(no_crate_inject, attr(deny(warnings))), 5 | test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))) 6 | )] 7 | 8 | pub mod ch01; -------------------------------------------------------------------------------- /tutorial/firstclass/01/01.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | let s = "hello world".to_string(); 4 | 5 | println!("地址:ss: {:p}\n,s:{:p}, len: {}, capacity: {}, size: {}", 6 | &"hello world", &s, s.len(), s.capacity(), std::mem::size_of_val(&s)); 7 | } -------------------------------------------------------------------------------- /tutorial/firstclass/02/02.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int hello() 4 | { 5 | printf("Hello World!\n"); 6 | 7 | return 0; 8 | } 9 | 10 | int main() 11 | { 12 | 13 | int (*p)() = &hello; 14 | (*p)(); 15 | 16 | int *p1 = (int *)p; 17 | p1[1]=0xdeadbeef; 18 | 19 | } 20 | 21 | /*output: 22 | Hello World! 23 | Segmentation fault 24 | */ -------------------------------------------------------------------------------- /tutorial/firstclass/02/02.rs: -------------------------------------------------------------------------------- 1 | const PI:f64 = 3.1415926; 2 | 3 | 4 | struct Rectangle { 5 | a: f64, 6 | b: f64, 7 | } // end of struct Rectangle 8 | 9 | 10 | struct Circle { 11 | r: f64, 12 | } // end of struct Circle 13 | 14 | struct Triangle { 15 | a: f64, 16 | b: f64, 17 | c: f64, 18 | } // end of struct Triangle 19 | 20 | 21 | enum Shape { 22 | Rectangle(Rectangle), 23 | Circle(Circle), 24 | Triangle(Triangle), 25 | } // end of enum Shape 26 | 27 | 28 | impl Shape { 29 | fn area(&self) -> f64 { 30 | match *self { 31 | Shape::Rectangle(ref r) => r.area(), 32 | Shape::Circle(ref c) => c.area(), 33 | Shape::Triangle(ref t) => t.area(), 34 | } 35 | } // end of fn area 36 | } // end of impl Shape 37 | 38 | 39 | 40 | trait Area { 41 | fn area(&self) -> f64; 42 | } // end of trait HasArea 43 | 44 | 45 | 46 | impl Area for Rectangle { 47 | fn area(&self) -> f64 { 48 | self.a * self.b 49 | } // end of fn area 50 | } // end of impl Rectangle 51 | 52 | impl Area for Circle { 53 | fn area(&self) -> f64 { 54 | PI * self.r * self.r 55 | } // end of fn area 56 | } // end of impl Circle 57 | 58 | impl Area for Triangle { 59 | fn area(&self) -> f64 { 60 | let (a, b, c) = (self.a, self.b, self.c); 61 | let p = (a + b + c) / 2.0; 62 | (p * (p - a) * (p - b) * (p - c)).sqrt() 63 | } // end of fn area 64 | 65 | } // end of impl Triangle 66 | 67 | 68 | fn main() { 69 | let rectangle = Rectangle { a: 3.0, b: 4.0 }; 70 | 71 | let shape = Shape::Rectangle(rectangle); 72 | 73 | println!("Area of rectangle: {}", shape.area()); 74 | 75 | } 76 | -------------------------------------------------------------------------------- /tutorial/firstclass/03/fib.rs: -------------------------------------------------------------------------------- 1 | 2 | fn fib_loop(n: u8) { 3 | let mut a = 1; 4 | let mut b = 1; 5 | let mut i = 2u8; 6 | 7 | loop { 8 | let c = a + b; 9 | a = b; 10 | b = c; 11 | i += 1; 12 | 13 | println!("next val is {}", b); 14 | 15 | if i >= n { 16 | break; 17 | } 18 | } 19 | } 20 | 21 | fn fib_while(n: u8) { 22 | let (mut a, mut b, mut i) = (1, 1, 2); 23 | 24 | while i < n { 25 | let c = a + b; 26 | a = b; 27 | b = c; 28 | i += 1; 29 | 30 | println!("next val is {}", b); 31 | } 32 | } 33 | 34 | fn fib_for(n: u8) { 35 | let (mut a, mut b) = (1, 1); 36 | 37 | for _i in 2..n { 38 | let c = a + b; 39 | a = b; 40 | b = c; 41 | println!("next val is {}", b); 42 | } 43 | } 44 | 45 | fn main() { 46 | let n = 10; 47 | fib_loop(n); 48 | fib_while(n); 49 | fib_for(n); 50 | } -------------------------------------------------------------------------------- /tutorial/firstclass/03/func.rs: -------------------------------------------------------------------------------- 1 | fn apply(value: i32, f: fn(i32) -> i32) -> i32 { 2 | 3 | f(value) 4 | 5 | } 6 | 7 | fn square(value: i32) -> i32 { 8 | 9 | value * value 10 | 11 | } 12 | 13 | fn cube(value: i32) -> i32 { 14 | 15 | value * value * value 16 | 17 | } 18 | 19 | fn main() { 20 | println!("apply square:{}", apply(2,square)); 21 | println!("apply cuba:{}", apply(2,cube)); 22 | 23 | } -------------------------------------------------------------------------------- /tutorial/firstclass/03/return.rs: -------------------------------------------------------------------------------- 1 | fn pi() -> f64 { 2 | 3.141592653589793 3 | } 4 | 5 | 6 | fn not_pi() { 7 | 3.141592653589793; 8 | // return unit 9 | } 10 | 11 | 12 | fn main() { 13 | let pi = pi(); 14 | let not_pi = not_pi(); 15 | 16 | println!("pi: {:?}\nnot_pi:{:?}", pi, not_pi); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /tutorial/firstclass/03/scrape_url/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "scrape_url" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | reqwest = { version = "0.11",features = ["blocking"] } 10 | html2md ="0.2" 11 | 12 | 13 | -------------------------------------------------------------------------------- /tutorial/firstclass/03/scrape_url/rust.md: -------------------------------------------------------------------------------- 1 | Rust Programming Language 2 | 3 | [![Rust Logo](/static/images/rust-logo-blk.svg) ](/) 4 | 5 | * [Install](/tools/install) 6 | * [Learn](/learn) 7 | * [Playground](https://play.rust-lang.org/) 8 | * [Tools](/tools) 9 | * [Governance](/governance) 10 | * [Community](/community) 11 | * [Blog](https://blog.rust-lang.org/) 12 | 13 | Language English (en-US)Español (es)Français (fr)Italiano (it)日本語 (ja)Português (pt-BR)Русский (ru)Türkçe (tr)简体中文 (zh-CN)正體中文 (zh-TW) 14 | 15 | Rust 16 | ========== 17 | 18 | A language empowering everyone 19 | to build reliable and efficient software. 20 | ---------- 21 | 22 | [ Get Started ](/learn/get-started) 23 | 24 | [Version 1.56.0](https://blog.rust-lang.org/2021/10/21/Rust-1.56.0.html) 25 | 26 | Why Rust? 27 | ---------- 28 | 29 | ### Performance ### 30 | 31 | Rust is blazingly fast and memory-efficient: with no runtime or 32 | garbage collector, it can power performance-critical services, run on 33 | embedded devices, and easily integrate with other languages. 34 | 35 | ### Reliability ### 36 | 37 | Rust’s rich type system and ownership model guarantee memory-safety 38 | and thread-safety — enabling you to eliminate many classes of 39 | bugs at compile-time. 40 | 41 | ### Productivity ### 42 | 43 | Rust has great documentation, a friendly compiler with useful error 44 | messages, and top-notch tooling — an integrated package manager 45 | and build tool, smart multi-editor support with auto-completion and 46 | type inspections, an auto-formatter, and more. 47 | 48 | Build it in Rust 49 | ---------- 50 | 51 | In 2018, the Rust community decided to improve programming experience 52 | for a few distinct domains (see [the 2018 53 | roadmap](https://blog.rust-lang.org/2018/03/12/roadmap.html)). For these, you can find many high-quality crates and some 54 | awesome guides on how to get started. 55 | 56 | ![terminal](/static/images/cli.svg) 57 | 58 | ### Command Line ### 59 | 60 | Whip up a CLI tool quickly with Rust’s robust ecosystem. 61 | Rust helps you maintain your app with confidence and distribute it with ease. 62 | 63 | [Building Tools](/what/cli) 64 | 65 | ![gear with puzzle piece elements](/static/images/webassembly.svg) 66 | 67 | ### WebAssembly ### 68 | 69 | Use Rust to supercharge your JavaScript, one module at a time. 70 | Publish to npm, bundle with webpack, and you’re off to the races. 71 | 72 | [Writing Web Apps](/what/wasm) 73 | 74 | ![a cloud with nodes](/static/images/networking.svg) 75 | 76 | ### Networking ### 77 | 78 | Predictable performance. Tiny resource footprint. Rock-solid reliability. 79 | Rust is great for network services. 80 | 81 | [Working On Servers](/what/networking) 82 | 83 | ![an embedded device chip](/static/images/embedded.svg) 84 | 85 | ### Embedded ### 86 | 87 | Targeting low-resource devices? 88 | Need low-level control without giving up high-level conveniences? 89 | Rust has you covered. 90 | 91 | [Starting With Embedded](/what/embedded) 92 | 93 | Rust in production 94 | ---------- 95 | 96 | Hundreds of companies around the world are using Rust in production 97 | today for fast, low-resource, cross-platform solutions. Software you know 98 | and love, like [Firefox](https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo/),[Dropbox](https://blogs.dropbox.com/tech/2016/06/lossless-compression-with-brotli/), 99 | and [Cloudflare](https://blog.cloudflare.com/cloudflare-workers-as-a-serverless-rust-platform/), 100 | uses Rust. **From startups to large 101 | corporations, from embedded devices to scalable web services, Rust is a great fit.** 102 | 103 | > My biggest compliment to Rust is that it's boring, and this is an amazing compliment. 104 | 105 | – Chris Dickinson, Engineer at npm, Inc 106 | 107 | [![npm Logo](/static/images/user-logos/npm.svg) ](https://www.npmjs.com/) 108 | 109 | --- 110 | 111 | [![Yelp Logo](/static/images/user-logos/yelp.png)](https://www.youtube.com/watch?v=u6ZbF4apABk) 112 | 113 | > All the documentation, the tooling, the community is great - you have all the tools to succeed in writing Rust code. 114 | 115 | – Antonio Verardi, Infrastructure Engineer 116 | 117 | [Learn More](/production) 118 | 119 | Get involved 120 | ---------- 121 | 122 | ### Read Rust ### 123 | 124 | We love documentation! Take a look at the books available online, as well as key blog posts and user guides. 125 | 126 | [Read the book](learn) 127 | 128 | ### Watch Rust ### 129 | 130 | The Rust community has a dedicated YouTube channel collecting a huge range of presentations and 131 | tutorials. 132 | 133 | [Watch the Videos](https://www.youtube.com/channel/UCaYhcUwRBNscFNUKTjgPFiA) 134 | 135 | ### Contribute code ### 136 | 137 | Rust is truly a community effort, and we welcome contribution from hobbyists and production users, from 138 | newcomers and seasoned professionals. Come help us make the Rust experience even better! 139 | 140 | [ Read Contribution Guide ](https://rustc-dev-guide.rust-lang.org/getting-started.html) 141 | 142 | Thanks 143 | ---------- 144 | 145 | Rust would not exist without the generous contributions of time, work, and resources from individuals and companies. We are very grateful for the support! 146 | 147 | ### Individuals ### 148 | 149 | Rust is a community project and is very thankful for the many community contributions it receives. 150 | 151 | [See individual contributors](https://thanks.rust-lang.org/) 152 | 153 | ### Corporate sponsors ### 154 | 155 | The Rust project receives support from companies through the donation of infrastructure. 156 | 157 | [See sponsors](/sponsors) 158 | 159 | #### Get help! #### 160 | 161 | * [Documentation](/learn) 162 | * [Rust Forge (Contributor Documentation)](http://forge.rust-lang.org) 163 | * [Ask a Question on the Users Forum](https://users.rust-lang.org) 164 | * [Check Website Status](http://ping.rust-lang.org) 165 | 166 | Language English (en-US)Español (es)Français (fr)Italiano (it)日本語 (ja)Português (pt-BR)Русский (ru)Türkçe (tr)简体中文 (zh-CN)正體中文 (zh-TW) 167 | 168 | #### Terms and policies #### 169 | 170 | * [Code of Conduct](/policies/code-of-conduct) 171 | * [Licenses](/policies/licenses) 172 | * [Logo Policy and Media Guide](/policies/media-guide) 173 | * [Security Disclosures](/policies/security) 174 | * [Privacy Policy](https://foundation.rust-lang.org/policies/privacy-policy/) 175 | * [All Policies](/policies) 176 | 177 | #### Social #### 178 | 179 | [![twitter logo](/static/images/twitter.svg "Twitter")](https://twitter.com/rustlang) [![youtube logo](/static/images/youtube.svg "YouTube")](https://www.youtube.com/channel/UCaYhcUwRBNscFNUKTjgPFiA) [![discord logo](/static/images/discord.svg "Discord")](https://discord.gg/rust-lang) [![github logo](/static/images/github.svg "GitHub")](https://github.com/rust-lang) 180 | 181 | Maintained by the Rust Team. See a bug?[File an issue!](https://github.com/rust-lang/www.rust-lang.org/issues/new/choose) 182 | 183 | Looking for the [previous website](https://prev.rust-lang.org)? -------------------------------------------------------------------------------- /tutorial/firstclass/03/scrape_url/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | fn main() -> Result<(), Box> { 4 | 5 | let url = "http://www.rust-lang.org/"; 6 | let output = "rust.md"; 7 | 8 | println!("链接地址:{}", url); 9 | 10 | let body = reqwest::blocking::get(url)?.text()?; 11 | 12 | println!("开始转换"); 13 | 14 | let md = html2md::parse_html(&body); 15 | 16 | fs::write(output, md.as_bytes())?; 17 | 18 | println!("转换完成,文件保存在:{}", output); 19 | 20 | Ok(()) 21 | } -------------------------------------------------------------------------------- /tutorial/firstclass/03/struct.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | 3 | enum Gender { 4 | Unspecified = 0, 5 | Female = 1, 6 | Male = 2, 7 | } 8 | 9 | #[derive(Debug, Copy,Clone)] 10 | struct UserId(u64); 11 | 12 | #[derive(Debug,Copy,Clone)] 13 | struct TopicId(u64); 14 | 15 | #[derive(Debug)] 16 | struct User { 17 | id: UserId, 18 | name: String, 19 | gender: Gender, 20 | } 21 | 22 | #[derive(Debug)] 23 | struct Topic { 24 | id: TopicId, 25 | name: String, 26 | owner: UserId, 27 | } 28 | 29 | #[derive(Debug)] 30 | enum Event { 31 | Join((UserId,TopicId)), 32 | Leave((UserId,TopicId)), 33 | Message((UserId,TopicId,String)), 34 | } 35 | 36 | 37 | fn porcess_event(event: &Event) { 38 | 39 | match event { 40 | Event::Join((user_id, topic_id)) => { 41 | println!("{:?} join topic {:?}", user_id, topic_id); 42 | }, 43 | Event::Leave((user_id, topic_id)) => { 44 | println!("{:?} leave topic {:?}", user_id, topic_id); 45 | }, 46 | Event::Message((user_id, topic_id, message)) => { 47 | println!("{:?} send message {:?} to topic {:?}", user_id, message, topic_id); 48 | } 49 | } 50 | } 51 | 52 | 53 | fn process_message( event: &Event) { 54 | 55 | if let Event::Message((user_id, topic_id, message)) = event { 56 | println!("{:?} send message {:?} to topic {:?}", user_id, message, topic_id); 57 | } 58 | 59 | } 60 | 61 | fn main() { 62 | 63 | let user1 = User { 64 | id: UserId(1), 65 | name: "Alice".to_string(), 66 | gender: Gender::Female 67 | }; 68 | 69 | let user2 = User { 70 | id: UserId(2), 71 | name: "Bob".to_string(), 72 | gender: Gender::Male 73 | }; 74 | 75 | let topic = Topic { id: TopicId(1), name: "new topic".to_string(), owner: UserId(1)}; 76 | 77 | let event1 = Event::Join((user1.id, topic.id)); 78 | let event2 = Event::Join((user2.id,topic.id)); 79 | let event3 = Event::Message((user1.id,topic.id,"hello".to_string())); 80 | 81 | 82 | println!("event1:{:?},event2:{:?},event3:{:?}",event1,event2,event3); 83 | 84 | } 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /tutorial/firstclass/03/test_tutorial/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_tutorial" 3 | version = "0.1.0" 4 | edition = "2018" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tutorial/firstclass/03/test_tutorial/src/main.rs: -------------------------------------------------------------------------------- 1 | 2 | pub fn sum(a:i32, b:i32) -> i32 { 3 | a + b 4 | } 5 | 6 | #[cfg(test)] 7 | mod tests { 8 | 9 | use super::*; 10 | 11 | #[test] 12 | fn test_sum() { 13 | assert_eq!(sum(1, 2), 3); 14 | } 15 | } 16 | 17 | 18 | fn main() { 19 | 20 | let sum = sum(1, 2); 21 | println!("{}", sum); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /tutorial/firstclass/04/HTTPie/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "httpie" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html[dependencies] 7 | 8 | [dependencies] 9 | anyhow = "1" # 错误处理 10 | clap = "3.0.0-beta.5" # 命令行解析 11 | colored = "2" # 命令终端多彩显示 12 | jsonxf = "1.1" # JSON pretty print 格式化 13 | mime = "0.3" # 处理 mime 类型 14 | # reqwest 默认使用 openssl,有些 linux 用户如果没有安装好 openssl 会无法编译,这里我改成了使用 rustls 15 | reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] } # HTTP 客户端 16 | tokio = { version = "1", features = ["full"] } # 异步处理库 17 | syntect = "4" -------------------------------------------------------------------------------- /tutorial/firstclass/04/HTTPie/src/main.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use clap::Parser; 3 | use colored::Colorize; 4 | use mime::Mime; 5 | use reqwest::{header, Client, Response, Url}; 6 | use std::{collections::HashMap, str::FromStr}; 7 | use syntect::{ 8 | easy::HighlightLines, 9 | highlighting::{Style, ThemeSet}, 10 | parsing::SyntaxSet, 11 | util::{as_24_bit_terminal_escaped, LinesWithEndings}, 12 | }; 13 | 14 | // 以下部分用于处理 CLI 15 | 16 | // 定义 httpie 的 CLI 的主入口,它包含若干个子命令 17 | // 下面 /// 的注释是文档,clap 会将其作为 CLI 的帮助 18 | 19 | /// A naive httpie implementation with Rust, can you imagine how easy it is? 20 | #[derive(Parser, Debug)] 21 | #[clap(version = "1.0", author = "Tyr Chen ")] 22 | struct Opts { 23 | #[clap(subcommand)] 24 | subcmd: SubCommand, 25 | } 26 | 27 | // 子命令分别对应不同的 HTTP 方法,目前只支持 get / post 28 | #[derive(Parser, Debug)] 29 | enum SubCommand { 30 | Get(Get), 31 | Post(Post), 32 | // 我们暂且不支持其它 HTTP 方法 33 | } 34 | 35 | // get 子命令 36 | 37 | /// feed get with an url and we will retrieve the response for you 38 | #[derive(Parser, Debug)] 39 | struct Get { 40 | /// HTTP 请求的 URL 41 | #[clap(parse(try_from_str = parse_url))] 42 | url: String, 43 | } 44 | 45 | // post 子命令。需要输入一个 url,和若干个可选的 key=value,用于提供 json body 46 | 47 | /// feed post with an url and optional key=value pairs. We will post the data 48 | /// as JSON, and retrieve the response for you 49 | #[derive(Parser, Debug)] 50 | struct Post { 51 | /// HTTP 请求的 URL 52 | #[clap(parse(try_from_str = parse_url))] 53 | url: String, 54 | /// HTTP 请求的 body 55 | #[clap(parse(try_from_str=parse_kv_pair))] 56 | body: Vec, 57 | } 58 | 59 | /// 命令行中的 key=value 可以通过 parse_kv_pair 解析成 KvPair 结构 60 | #[derive(Debug, PartialEq)] 61 | struct KvPair { 62 | k: String, 63 | v: String, 64 | } 65 | 66 | /// 当我们实现 FromStr trait 后,可以用 str.parse() 方法将字符串解析成 KvPair 67 | impl FromStr for KvPair { 68 | type Err = anyhow::Error; 69 | 70 | fn from_str(s: &str) -> Result { 71 | // 使用 = 进行 split,这会得到一个迭代器 72 | let mut split = s.split('='); 73 | let err = || anyhow!(format!("Failed to parse {}", s)); 74 | Ok(Self { 75 | // 从迭代器中取第一个结果作为 key,迭代器返回 Some(T)/None 76 | // 我们将其转换成 Ok(T)/Err(E),然后用 ? 处理错误 77 | k: (split.next().ok_or_else(err)?).to_string(), 78 | // 从迭代器中取第二个结果作为 value 79 | v: (split.next().ok_or_else(err)?).to_string(), 80 | }) 81 | } 82 | } 83 | 84 | /// 因为我们为 KvPair 实现了 FromStr,这里可以直接 s.parse() 得到 KvPair 85 | fn parse_kv_pair(s: &str) -> Result { 86 | s.parse() 87 | } 88 | 89 | fn parse_url(s: &str) -> Result { 90 | // 这里我们仅仅检查一下 URL 是否合法 91 | let _url: Url = s.parse()?; 92 | 93 | Ok(s.into()) 94 | } 95 | 96 | /// 处理 get 子命令 97 | async fn get(client: Client, args: &Get) -> Result<()> { 98 | let resp = client.get(&args.url).send().await?; 99 | Ok(print_resp(resp).await?) 100 | } 101 | 102 | /// 处理 post 子命令 103 | async fn post(client: Client, args: &Post) -> Result<()> { 104 | let mut body = HashMap::new(); 105 | for pair in args.body.iter() { 106 | body.insert(&pair.k, &pair.v); 107 | } 108 | let resp = client.post(&args.url).json(&body).send().await?; 109 | Ok(print_resp(resp).await?) 110 | } 111 | 112 | // 打印服务器版本号 + 状态码 113 | fn print_status(resp: &Response) { 114 | let status = format!("{:?} {}", resp.version(), resp.status()).blue(); 115 | println!("{}\n", status); 116 | } 117 | 118 | // 打印服务器返回的 HTTP header 119 | fn print_headers(resp: &Response) { 120 | for (name, value) in resp.headers() { 121 | println!("{}: {:?}", name.to_string().green(), value); 122 | } 123 | 124 | println!(); 125 | } 126 | 127 | /// 打印服务器返回的 HTTP body 128 | fn print_body(m: Option, body: &str) { 129 | match m { 130 | // 对于 "application/json" 我们 pretty print 131 | Some(v) if v == mime::APPLICATION_JSON => print_syntect(body, "json"), 132 | Some(v) if v == mime::TEXT_HTML => print_syntect(body, "html"), 133 | 134 | // 其它 mime type,我们就直接输出 135 | _ => println!("{}", body), 136 | } 137 | } 138 | 139 | /// 打印整个响应 140 | async fn print_resp(resp: Response) -> Result<()> { 141 | print_status(&resp); 142 | print_headers(&resp); 143 | let mime = get_content_type(&resp); 144 | let body = resp.text().await?; 145 | print_body(mime, &body); 146 | Ok(()) 147 | } 148 | 149 | /// 将服务器返回的 content-type 解析成 Mime 类型 150 | fn get_content_type(resp: &Response) -> Option { 151 | resp.headers() 152 | .get(header::CONTENT_TYPE) 153 | .map(|v| v.to_str().unwrap().parse().unwrap()) 154 | } 155 | 156 | /// 程序的入口函数,因为在 http 请求时我们使用了异步处理,所以这里引入 tokio 157 | #[tokio::main] 158 | async fn main() -> Result<()> { 159 | let opts: Opts = Opts::parse(); 160 | let mut headers = header::HeaderMap::new(); 161 | // 为我们的 http 客户端添加一些缺省的 HTTP 头 162 | headers.insert("X-POWERED-BY", "Rust".parse()?); 163 | headers.insert(header::USER_AGENT, "Rust Httpie".parse()?); 164 | let client = reqwest::Client::builder() 165 | .default_headers(headers) 166 | .build()?; 167 | let result = match opts.subcmd { 168 | SubCommand::Get(ref args) => get(client, args).await?, 169 | SubCommand::Post(ref args) => post(client, args).await?, 170 | }; 171 | 172 | Ok(result) 173 | } 174 | 175 | fn print_syntect(s: &str, ext: &str) { 176 | // Load these once at the start of your program 177 | let ps = SyntaxSet::load_defaults_newlines(); 178 | let ts = ThemeSet::load_defaults(); 179 | let syntax = ps.find_syntax_by_extension(ext).unwrap(); 180 | let mut h = HighlightLines::new(syntax, &ts.themes["base16-ocean.dark"]); 181 | for line in LinesWithEndings::from(s) { 182 | let ranges: Vec<(Style, &str)> = h.highlight(line, &ps); 183 | let escaped = as_24_bit_terminal_escaped(&ranges[..], true); 184 | print!("{}", escaped); 185 | } 186 | } 187 | 188 | // 仅在 cargo test 时才编译 189 | #[cfg(test)] 190 | mod tests { 191 | use super::*; 192 | 193 | #[test] 194 | fn parse_url_works() { 195 | assert!(parse_url("abc").is_err()); 196 | assert!(parse_url("http://abc.xyz").is_ok()); 197 | assert!(parse_url("https://httpbin.org/post").is_ok()); 198 | } 199 | 200 | #[test] 201 | fn parse_kv_pair_works() { 202 | assert!(parse_kv_pair("a").is_err()); 203 | assert_eq!( 204 | parse_kv_pair("a=1").unwrap(), 205 | KvPair { 206 | k: "a".into(), 207 | v: "1".into() 208 | } 209 | ); 210 | 211 | assert_eq!( 212 | parse_kv_pair("b=").unwrap(), 213 | KvPair { 214 | k: "b".into(), 215 | v: "".into() 216 | } 217 | ); 218 | } 219 | } -------------------------------------------------------------------------------- /tutorial/firstclass/05/thumbor/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "thumbor" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tutorial/firstclass/05/thumbor/src/main.rs: -------------------------------------------------------------------------------- 1 | /** 2 | * 图片服务器:先做resize,再添加水印,再使用一个滤镜 3 | */ 4 | 5 | 6 | /* 图片操作类 */ 7 | struct ImageSpec { 8 | 9 | specs: Vec, 10 | } 11 | 12 | 13 | /* 图片操作行为 */ 14 | enum Spec { 15 | Resize(Resize), 16 | Crop(Crop), 17 | } 18 | 19 | /* 添加水印 */ 20 | struct Crop { 21 | 22 | } 23 | 24 | 25 | /* 缩小尺寸 */ 26 | struct Resize { 27 | 28 | width: u32, 29 | height: u32, 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /tutorial/firstclass/06/queryer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "queryer" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tutorial/firstclass/06/queryer/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | #[test] 4 | fn it_works() { 5 | let result = 2 + 2; 6 | assert_eq!(result, 4); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tutorial/firstclass/07/find_pos.rs: -------------------------------------------------------------------------------- 1 | 2 | fn find_pos(data: Vec, v: u32) -> Option { 3 | 4 | for(i,item) in data.iter().enumerate() { 5 | if *item == v { 6 | return Some(i); 7 | } 8 | } 9 | None 10 | } 11 | 12 | fn main() { 13 | 14 | let data =vec![1,0,42,99,90,11]; 15 | 16 | let v = 42; 17 | 18 | if let Some(pos) = find_pos(data,v) { 19 | println!("found {} at position {}",v,pos); 20 | } else { 21 | println!("{} not found",v); 22 | } 23 | } 24 | 25 | 26 | -------------------------------------------------------------------------------- /tutorial/firstclass/08/local_ref.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | let a = local_ref(); 4 | println!("{}", a); 5 | } 6 | 7 | fn local_ref<`a>() -> &`a i32 { 8 | let a = 1; 9 | &a 10 | } -------------------------------------------------------------------------------- /tutorial/firstclass/08/local_vec.rs: -------------------------------------------------------------------------------- 1 | 2 | fn main() { 3 | let mut data: Vec<&u32> = Vec::new(); 4 | push_local_ref(&mut data); 5 | println!("data: {:?}", data); 6 | } 7 | 8 | fn push_local_ref(data: &mut Vec<&u32>) { 9 | let v = 42; 10 | data.push(&v); 11 | } 12 | /* 13 | fn main() { 14 | 15 | let mut data = Vec::new(); 16 | 17 | let v = 42; 18 | 19 | data.push(v); 20 | 21 | println!("{:?}", data); 22 | } 23 | */ -------------------------------------------------------------------------------- /tutorial/firstclass/08/sum.rs: -------------------------------------------------------------------------------- 1 | fn sum(data: &Vec) -> u32 { 2 | 3 | data.iter().fold(0, |acc, x| acc + x) 4 | } 5 | 6 | fn main() { 7 | 8 | let data = vec![1, 2, 3, 4, 5]; 9 | let data1 = &data; 10 | 11 | let result1 = sum(data1); 12 | println!("{}", result1); 13 | } -------------------------------------------------------------------------------- /tutorial/firstclass/09/dag.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | #[derive(Debug)] 4 | struct Node { 5 | id: u32, 6 | downsteam: Option>, 7 | } 8 | 9 | impl Node { 10 | 11 | pub fn new(id:u32) -> Self { 12 | Self { id, downsteam: None, } 13 | 14 | } 15 | 16 | pub fn add_downstream(&mut self, downsteam: Rc) { 17 | self.downsteam = Some(downsteam); 18 | } 19 | 20 | 21 | pub fn get_downstream(&self) -> Option> { 22 | self.downsteam.as_ref().map(|x| x.clone()) 23 | } 24 | } 25 | 26 | fn main() { 27 | 28 | let mut node1 = Node::new(1); 29 | let mut node2 = Node::new(2); 30 | let mut node3 = Node::new(3); 31 | 32 | let node4 = Node::new(4); 33 | node3.add_downstream(Rc::new(node4)); 34 | 35 | node1.add_downstream(Rc::new(node3)); 36 | node2.add_downstream(node1.get_downstream().unwrap()); 37 | 38 | println!("node1: {:?},node2: {:?}", node1, node2) 39 | 40 | } -------------------------------------------------------------------------------- /tutorial/firstclass/09/rc.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | fn main() { 4 | let a = Rc::new(1); 5 | println!("{}", a); 6 | 7 | let b = a.clone(); 8 | println!("{}", b); 9 | 10 | let c = a.clone(); 11 | println!("{}", c); 12 | 13 | 14 | } -------------------------------------------------------------------------------- /tutorial/firstclass/10/lifetime.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | 3 | let x: u32; 4 | 5 | { 6 | let y = 42; 7 | let x = &y; 8 | 9 | } 10 | 11 | println!("x:{}", x); 12 | } -------------------------------------------------------------------------------- /tutorial/firstclass/10/max.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let s1 = String::from("Lindsey"); 3 | let s2 = String::from("Rosie"); 4 | 5 | let result =get_max( &s1, &s2 ); 6 | 7 | println!("bigger one:{}", result); 8 | } 9 | 10 | /* 11 | fn max(s1: &str, s2: &str) -> &str { 12 | if s1 > s2 { s1 } else { s2 } 13 | }*/ 14 | 15 | 16 | fn get_max<'a>(s1: &'a str, s2: &'a str) ->&'a str { 17 | 18 | if s1 > s2 { s1 } else { s2 } 19 | } -------------------------------------------------------------------------------- /tutorial/firstclass/10/strtok.rs: -------------------------------------------------------------------------------- 1 | pub fn strtok<'b,'a>(s: &'b mut &'a str, delimiter: char) -> &'a str { 2 | if let Some(i) = s.find(delimiter) { 3 | let prefix = &s[..i]; 4 | 5 | let suffix = &s[(i +delimiter.len_utf8())..]; 6 | *s = suffix; 7 | prefix 8 | } else { 9 | let prefix = *s; 10 | *s = ""; 11 | prefix 12 | } 13 | } 14 | 15 | 16 | fn main() { 17 | 18 | let s = "hello world".to_owned(); 19 | 20 | let mut s1 = s.as_str(); 21 | let hello = strtok(&mut s1, ' '); 22 | 23 | println!("hello is: {}, s1: {}, s:{}", hello, s1, s); 24 | } -------------------------------------------------------------------------------- /tutorial/firstclass/11/enum.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::collections::HashMap; 3 | use std::mem::size_of; 4 | 5 | enum E { 6 | A(f64), 7 | B(HashMap), 8 | C(Result, String>), 9 | } 10 | 11 | // 这是一个声明宏,它会打印各种数据结构本身的大小,在 Option 中的大小,以及在 Result 中的大小 12 | macro_rules! show_size { 13 | (header) => { 14 | println!( 15 | "{:<24} {:>4} {} {}", 16 | "Type", "T", "Option", "Result" 17 | ); 18 | println!("{}", "-".repeat(64)); 19 | }; 20 | ($t:ty) => { 21 | println!( 22 | "{:<24} {:4} {:8} {:12}", 23 | stringify!($t), 24 | size_of::<$t>(), 25 | size_of::>(), 26 | size_of::>(), 27 | ) 28 | }; 29 | } 30 | 31 | fn main() { 32 | show_size!(header); 33 | show_size!(u8); 34 | show_size!(f64); 35 | show_size!(&u8); 36 | show_size!(Box); 37 | show_size!(&[u8]); 38 | 39 | show_size!(String); 40 | show_size!(Vec); 41 | show_size!(HashMap); 42 | show_size!(E); 43 | } -------------------------------------------------------------------------------- /tutorial/firstclass/11/struct.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct S1 { 4 | u_int8_t a; 5 | u_int16_t b; 6 | u_int8_t c; 7 | }; 8 | 9 | struct S2 { 10 | u_int8_t a; 11 | u_int8_t b; 12 | u_int16_t c; 13 | }; 14 | 15 | int main() { 16 | 17 | printf("size of S1: %d\n size of S2: %d\n",sizeof(struct S1),sizeof(struct S2)); 18 | 19 | return 0; 20 | 21 | } -------------------------------------------------------------------------------- /tutorial/firstclass/11/struct.rs: -------------------------------------------------------------------------------- 1 | use std::mem::{align_of, size_of}; 2 | 3 | struct S1 { 4 | a:u8, 5 | b:u16, 6 | c:u8, 7 | } 8 | 9 | struct S2 { 10 | a:u8, 11 | b:u8, 12 | c:u16, 13 | } 14 | 15 | fn main() { 16 | println!("size of S1: {}", size_of::()); 17 | println!("size of S2: {}", size_of::()); 18 | 19 | println!("align of S1: {}", align_of::()); 20 | println!("align of S2: {}", align_of::()) 21 | } -------------------------------------------------------------------------------- /tutorial/firstclass/12/const.rs: -------------------------------------------------------------------------------- 1 | 2 | const PI: f64 = 3.1415926; 3 | static E: f32 = 2.71828; 4 | 5 | fn main() { 6 | const V: u32 = 10; 7 | static V1: &str = "hello"; 8 | println!("PI: {}, E: {}, V {}, V1: {}", PI, E, V, V1); 9 | } -------------------------------------------------------------------------------- /tutorial/firstclass/12/homework.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::io::{BufWriter, Write}; 3 | use std::net::TcpStream; 4 | 5 | #[derive(Debug)] 6 | struct MyWriter { 7 | writer: W, 8 | } 9 | 10 | impl MyWriter { 11 | pub fn new(addr: &str) -> MyWriter> { 12 | let stream = TcpStream::connect("127.0.0.1:8080").unwrap(); 13 | MyWriter { 14 | writer: BufWriter::new(stream), 15 | } 16 | } 17 | 18 | pub fn write(&mut self, buf: &str) -> std::io::Result<()> { 19 | self.writer.write_all(buf.as_bytes()) 20 | } 21 | } 22 | 23 | fn main() { 24 | let mut writer = MyWriter::>::new("127.0.0.1:8080"); 25 | writer.write("hello world!"); 26 | } 27 | -------------------------------------------------------------------------------- /tutorial/firstclass/12/id.rs: -------------------------------------------------------------------------------- 1 | 2 | fn id(x: T) -> T { 3 | return x; 4 | } 5 | 6 | fn main() { 7 | let int = id(10); 8 | let string = id("Tyr"); 9 | println!("{}, {}", int, string); 10 | } -------------------------------------------------------------------------------- /tutorial/firstclass/12/map.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | 3 | fn main() { 4 | 5 | let mut map = BTreeMap::new(); 6 | map.insert("blue", 10); 7 | 8 | println!("map: {:?}", map); 9 | } -------------------------------------------------------------------------------- /tutorial/firstclass/12/readfile.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fs::File; 3 | use std::io::{BufReader, Read, Result}; 4 | 5 | // 定义一个带有泛型参数 R 的 reader,此处我们不限制 R 6 | struct MyReader { 7 | reader: R, 8 | buf: String, 9 | } 10 | 11 | // 实现 new 函数时,我们不需要限制 R 12 | impl MyReader { 13 | pub fn new(reader: R) -> Self { 14 | Self { 15 | reader, 16 | buf: String::with_capacity(1024), 17 | } 18 | } 19 | } 20 | 21 | // 定义 process 时,我们需要用到 R 的方法,此时我们限制 R 必须实现 Read trait 22 | impl MyReader 23 | where 24 | R: Read, 25 | { 26 | pub fn process(&mut self) -> Result { 27 | self.reader.read_to_string(&mut self.buf) 28 | } 29 | } 30 | 31 | fn main() { 32 | // 在 windows 下,你需要换个文件读取,否则会出错 33 | let f = File::open("/etc/hosts").unwrap(); 34 | let mut reader = MyReader::new(BufReader::new(f)); 35 | 36 | let size = reader.process().unwrap(); 37 | println!("total size read: {}", size); 38 | } 39 | -------------------------------------------------------------------------------- /tutorial/firstclass/12/turbofish.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | 3 | fn main() { 4 | let addr = "127.0.0.1:8080".parse::().unwrap(); 5 | 6 | println!("ip address: {:?}, port: {:?}", addr.ip(), addr.port()); 7 | } -------------------------------------------------------------------------------- /tutorial/firstclass/12/var.rs: -------------------------------------------------------------------------------- 1 | 2 | fn main() { 3 | 4 | let numbers = vec![1,2,3,4,5,6,7,8,9,10]; 5 | 6 | let even_numbers: Vec<_> = numbers.into_iter().filter(|&x| x % 2 == 0).collect(); 7 | 8 | println!("{:?}", even_numbers); 9 | } -------------------------------------------------------------------------------- /tutorial/firstclass/13/trait_tutorial/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "trait_tutorial" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /tutorial/firstclass/13/trait_tutorial/src/animal.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt::{Debug, Display}; 3 | use std::mem::transmute; 4 | 5 | fn main() { 6 | let s1 = String::from("hello world!"); 7 | let s2 = String::from("goodbye world!"); 8 | // Display / Debug trait object for s 9 | let w1: &dyn Display = &s1; 10 | let w2: &dyn Debug = &s1; 11 | 12 | // Display / Debug trait object for s1 13 | let w3: &dyn Display = &s2; 14 | let w4: &dyn Debug = &s2; 15 | 16 | // 强行把 triat object 转换成两个地址 (usize, usize) 17 | // 这是不安全的,所以是 unsafe 18 | let (addr1, vtable1): (usize, usize) = unsafe { transmute(w1) }; 19 | let (addr2, vtable2): (usize, usize) = unsafe { transmute(w2) }; 20 | let (addr3, vtable3): (usize, usize) = unsafe { transmute(w3) }; 21 | let (addr4, vtable4): (usize, usize) = unsafe { transmute(w4) }; 22 | 23 | // s 和 s1 在栈上的地址,以及 main 在 TEXT 段的地址 24 | println!( 25 | "s1: {:p}, s2: {:p}, main(): {:p}", 26 | &s1, &s2, main as *const () 27 | ); 28 | // trait object(s / Display) 的 ptr 地址和 vtable 地址 29 | println!("addr1: 0x{:x}, vtable1: 0x{:x}", addr1, vtable1); 30 | // trait object(s / Debug) 的 ptr 地址和 vtable 地址 31 | println!("addr2: 0x{:x}, vtable2: 0x{:x}", addr2, vtable2); 32 | 33 | // trait object(s1 / Display) 的 ptr 地址和 vtable 地址 34 | println!("addr3: 0x{:x}, vtable3: 0x{:x}", addr3, vtable3); 35 | 36 | // trait object(s1 / Display) 的 ptr 地址和 vtable 地址 37 | println!("addr4: 0x{:x}, vtable4: 0x{:x}", addr4, vtable4); 38 | 39 | // 指向同一个数据的 trait object 其 ptr 地址相同 40 | assert_eq!(addr1, addr2); 41 | assert_eq!(addr3, addr4); 42 | 43 | // 指向同一种类型的同一个 trait 的 vtable 地址相同 44 | // 这里都是 String + Display 45 | assert_eq!(vtable1, vtable3); 46 | // 这里都是 String + Debug 47 | assert_eq!(vtable2, vtable4); 48 | } -------------------------------------------------------------------------------- /tutorial/firstclass/13/trait_tutorial/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | use std::io::Write; 3 | 4 | struct BufBuilder { 5 | buf: Vec, 6 | } 7 | 8 | impl BufBuilder { 9 | pub fn new() -> Self { 10 | Self { buf: Vec::with_capacity(1024), } 11 | } 12 | } 13 | 14 | impl fmt::Debug for BufBuilder { 15 | 16 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 17 | write!(f, "{}", String::from_utf8_lossy(&self.buf)) 18 | } 19 | } 20 | 21 | impl Write for BufBuilder { 22 | fn write(&mut self, buf: &[u8]) -> std::io::Result { 23 | // 把 buf 添加到 BufBuilder 的尾部 24 | self.buf.extend_from_slice(buf); 25 | Ok(buf.len()) 26 | } 27 | 28 | fn flush(&mut self) -> std::io::Result<()> { 29 | // 由于是在内存中操作,所以不需要 flush 30 | Ok(()) 31 | } 32 | } 33 | 34 | 35 | fn main() { 36 | let mut buf = BufBuilder::new(); 37 | buf.write_all(b"Hello world!").unwrap(); 38 | println!("{:?}", buf); 39 | } 40 | -------------------------------------------------------------------------------- /tutorial/firstclass/13/trait_tutorial/src/parser.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | pub trait Parse { 3 | fn parse(s: &str) -> Self; 4 | } 5 | 6 | impl Parse for u8 { 7 | fn parse(s: &str) -> Self { 8 | let re: Regex = Regex::new(r"^[0-9]+").unwrap(); 9 | if let Some(captures) = re.captures(s) { 10 | // 取第一个 match,将其捕获的 digits 换成 u8 11 | captures 12 | .get(0) 13 | .map_or(0, |s| s.as_str().parse().unwrap_or(0)) 14 | } else { 15 | 0 16 | } 17 | } 18 | } 19 | 20 | #[test] 21 | fn parse_should_work() { 22 | assert_eq!(u8::parse("123abcd"), 123); 23 | assert_eq!(u8::parse("1234abcd"), 0); 24 | assert_eq!(u8::parse("abcd"), 0); 25 | } 26 | 27 | fn main() { 28 | println!("result: {}", u8::parse("255 hello world")); 29 | } -------------------------------------------------------------------------------- /tutorial/firstclass/14/clone_trait.rs: -------------------------------------------------------------------------------- 1 | 2 | #[derive(Clone, Debug)] 3 | struct Developer { 4 | name: String, 5 | age: u8, 6 | lang: Language 7 | } 8 | 9 | #[allow(dead_code)] 10 | #[derive(Clone, Debug)] 11 | enum Language { 12 | Rust, 13 | TypeScript, 14 | Elixir, 15 | Haskell 16 | } 17 | 18 | fn main() { 19 | let dev = Developer { 20 | name: "Tyr".to_string(), 21 | age: 18, 22 | lang: Language::Rust 23 | }; 24 | let dev1 = dev.clone(); 25 | println!("dev: {:?}, addr of dev name: {:p}", dev, dev.name.as_str()); 26 | println!("dev1: {:?}, addr of dev1 name: {:p}", dev1, dev1.name.as_str()) 27 | } -------------------------------------------------------------------------------- /tutorial/firstclass/14/debug.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::fmt; 3 | // struct 可以 derive Default,但我们需要所有字段都实现了 Default 4 | #[derive(Clone, Debug, Default)] 5 | struct Developer { 6 | name: String, 7 | age: u8, 8 | lang: Language, 9 | } 10 | 11 | // enum 不能 derive Default 12 | #[allow(dead_code)] 13 | #[derive(Clone, Debug)] 14 | enum Language { 15 | Rust, 16 | TypeScript, 17 | Elixir, 18 | Haskell, 19 | } 20 | 21 | // 手工实现 Default 22 | impl Default for Language { 23 | fn default() -> Self { 24 | Language::Rust 25 | } 26 | } 27 | 28 | impl Developer { 29 | pub fn new(name: &str) -> Self { 30 | // 用 ..Default::default() 为剩余字段使用缺省值 31 | Self { 32 | name: name.to_owned(), 33 | ..Default::default() 34 | } 35 | } 36 | } 37 | 38 | impl fmt::Display for Developer { 39 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 40 | write!( 41 | f, 42 | "{}({} years old): {:?} developer", 43 | self.name, self.age, self.lang 44 | ) 45 | } 46 | } 47 | 48 | fn main() { 49 | // 使用 T::default() 50 | let dev1 = Developer::default(); 51 | // 使用 Default::default(),但此时类型无法通过上下文推断,需要提供类型 52 | let dev2: Developer = Default::default(); 53 | // 使用 T::new 54 | let dev3 = Developer::new("Tyr"); 55 | println!("dev1: {}\\ndev2: {}\\ndev3: {:?}", dev1, dev2, dev3); 56 | } -------------------------------------------------------------------------------- /tutorial/firstclass/14/ipadrr.rs: -------------------------------------------------------------------------------- 1 | 2 | use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; 3 | 4 | fn print(v: impl Into) { 5 | println!("{:?}", v.into()); 6 | } 7 | 8 | fn main() { 9 | let v4: Ipv4Addr = "2.2.2.2".parse().unwrap(); 10 | let v6: Ipv6Addr = "::1".parse().unwrap(); 11 | 12 | // IPAddr 实现了 From<[u8; 4],转换 IPv4 地址 13 | print([1, 1, 1, 1]); 14 | // IPAddr 实现了 From<[u16; 8],转换 IPv6 地址 15 | print([0xfe80, 0, 0, 0, 0xaede, 0x48ff, 0xfe00, 0x1122]); 16 | // IPAddr 实现了 From 17 | print(v4); 18 | // IPAddr 实现了 From 19 | print(v6); 20 | } -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/README.md: -------------------------------------------------------------------------------- 1 | # Exercise to Book Chapter mapping 2 | 3 | | Exercise | Book Chapter | 4 | |------------------------|--------------| 5 | | variables | §3.1 | 6 | | functions | §3.3 | 7 | | if | §3.5 | 8 | | move_semantics | §4.1 | 9 | | primitive_types | §4.3 | 10 | | structs | §5.1 | 11 | | enums | §6 | 12 | | modules | §7 | 13 | | collections | §8.1, §8.3 | 14 | | strings | §8.2 | 15 | | error_handling | §9 | 16 | | generics | §10 | 17 | | option | §10.1 | 18 | | traits | §10.2 | 19 | | tests | §11.1 | 20 | | standard_library_types | §13.2 | 21 | | threads | §16.1 | 22 | | macros | §19.6 | 23 | | clippy | n/a | 24 | | conversions | n/a | 25 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/advanced_errors/advanced_errs1.rs: -------------------------------------------------------------------------------- 1 | // advanced_errs1.rs 2 | 3 | // Remember back in errors6, we had multiple mapping functions so that we 4 | // could translate lower-level errors into our custom error type using 5 | // `map_err()`? What if we could use the `?` operator directly instead? 6 | 7 | // Make this code compile! Execute `rustlings hint advanced_errs1` for 8 | // hints :) 9 | 10 | // I AM NOT DONE 11 | 12 | use std::num::ParseIntError; 13 | use std::str::FromStr; 14 | 15 | // This is a custom error type that we will be using in the `FromStr` 16 | // implementation. 17 | #[derive(PartialEq, Debug)] 18 | enum ParsePosNonzeroError { 19 | Creation(CreationError), 20 | ParseInt(ParseIntError), 21 | } 22 | 23 | impl From for ParsePosNonzeroError { 24 | fn from(e: CreationError) -> Self { 25 | // TODO: complete this implementation so that the `?` operator will 26 | // work for `CreationError` 27 | } 28 | } 29 | 30 | // TODO: implement another instance of the `From` trait here so that the 31 | // `?` operator will work in the other place in the `FromStr` 32 | // implementation below. 33 | 34 | // Don't change anything below this line. 35 | 36 | impl FromStr for PositiveNonzeroInteger { 37 | type Err = ParsePosNonzeroError; 38 | fn from_str(s: &str) -> Result { 39 | let x: i64 = s.parse()?; 40 | Ok(PositiveNonzeroInteger::new(x)?) 41 | } 42 | } 43 | 44 | #[derive(PartialEq, Debug)] 45 | struct PositiveNonzeroInteger(u64); 46 | 47 | #[derive(PartialEq, Debug)] 48 | enum CreationError { 49 | Negative, 50 | Zero, 51 | } 52 | 53 | impl PositiveNonzeroInteger { 54 | fn new(value: i64) -> Result { 55 | match value { 56 | x if x < 0 => Err(CreationError::Negative), 57 | x if x == 0 => Err(CreationError::Zero), 58 | x => Ok(PositiveNonzeroInteger(x as u64)), 59 | } 60 | } 61 | } 62 | 63 | #[cfg(test)] 64 | mod test { 65 | use super::*; 66 | 67 | #[test] 68 | fn test_parse_error() { 69 | // We can't construct a ParseIntError, so we have to pattern match. 70 | assert!(matches!( 71 | PositiveNonzeroInteger::from_str("not a number"), 72 | Err(ParsePosNonzeroError::ParseInt(_)) 73 | )); 74 | } 75 | 76 | #[test] 77 | fn test_negative() { 78 | assert_eq!( 79 | PositiveNonzeroInteger::from_str("-555"), 80 | Err(ParsePosNonzeroError::Creation(CreationError::Negative)) 81 | ); 82 | } 83 | 84 | #[test] 85 | fn test_zero() { 86 | assert_eq!( 87 | PositiveNonzeroInteger::from_str("0"), 88 | Err(ParsePosNonzeroError::Creation(CreationError::Zero)) 89 | ); 90 | } 91 | 92 | #[test] 93 | fn test_positive() { 94 | let x = PositiveNonzeroInteger::new(42); 95 | assert!(x.is_ok()); 96 | assert_eq!(PositiveNonzeroInteger::from_str("42"), Ok(x.unwrap())); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/clippy/README.md: -------------------------------------------------------------------------------- 1 | # Clippy 2 | 3 | The Clippy tool is a collection of lints to analyze your code so you can catch common mistakes and improve your Rust code. 4 | 5 | If you used the installation script for Rustlings, Clippy should be already installed. 6 | If not you can install it manually via `rustup component add clippy`. 7 | 8 | ## Further information 9 | 10 | - [GitHub Repository](https://github.com/rust-lang/rust-clippy). 11 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/clippy/clippy1.rs: -------------------------------------------------------------------------------- 1 | // clippy1.rs 2 | // The Clippy tool is a collection of lints to analyze your code 3 | // so you can catch common mistakes and improve your Rust code. 4 | // 5 | // For these exercises the code will fail to compile when there are clippy warnings 6 | // check clippy's suggestions from the output to solve the exercise. 7 | // Execute `rustlings hint clippy1` for hints :) 8 | 9 | // I AM NOT DONE 10 | 11 | fn main() { 12 | let x = 1.2331f64; 13 | let y = 1.2332f64; 14 | if y != x { 15 | println!("Success!"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/clippy/clippy2.rs: -------------------------------------------------------------------------------- 1 | // clippy2.rs 2 | // Make me compile! Execute `rustlings hint clippy2` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let mut res = 42; 8 | let option = Some(12); 9 | for x in option { 10 | res += x; 11 | } 12 | println!("{}", res); 13 | } 14 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/collections/README.md: -------------------------------------------------------------------------------- 1 | # Collections 2 | 3 | Rust’s standard library includes a number of very useful data 4 | structures called collections. Most other data types represent one 5 | specific value, but collections can contain multiple values. Unlike 6 | the built-in array and tuple types, the data these collections point 7 | to is stored on the heap, which means the amount of data does not need 8 | to be known at compile time and can grow or shrink as the program 9 | runs. 10 | 11 | This exercise will get you familiar with two fundamental data 12 | structures that are used very often in Rust programs: 13 | 14 | * A *vector* allows you to store a variable number of values next to 15 | each other. 16 | * A *hash map* allows you to associate a value with a particular key. 17 | You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map), 18 | [*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages. 19 | 20 | ## Further information 21 | 22 | - [Storing Lists of Values with Vectors](https://doc.rust-lang.org/stable/book/ch08-01-vectors.html) 23 | - [Storing Keys with Associated Values in Hash Maps](https://doc.rust-lang.org/book/ch08-03-hash-maps.html) 24 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/collections/hashmap1.rs: -------------------------------------------------------------------------------- 1 | // hashmap1.rs 2 | // A basket of fruits in the form of a hash map needs to be defined. 3 | // The key represents the name of the fruit and the value represents 4 | // how many of that particular fruit is in the basket. You have to put 5 | // at least three different types of fruits (e.g apple, banana, mango) 6 | // in the basket and the total count of all the fruits should be at 7 | // least five. 8 | // 9 | // Make me compile and pass the tests! 10 | // 11 | // Execute the command `rustlings hint hashmap1` if you need 12 | // hints. 13 | 14 | // I AM NOT DONE 15 | 16 | use std::collections::HashMap; 17 | 18 | fn fruit_basket() -> HashMap { 19 | let mut basket = // TODO: declare your hash map here. 20 | 21 | // Two bananas are already given for you :) 22 | basket.insert(String::from("banana"), 2); 23 | 24 | // TODO: Put more fruits in your basket here. 25 | 26 | basket 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn at_least_three_types_of_fruits() { 35 | let basket = fruit_basket(); 36 | assert!(basket.len() >= 3); 37 | } 38 | 39 | #[test] 40 | fn at_least_five_fruits() { 41 | let basket = fruit_basket(); 42 | assert!(basket.values().sum::() >= 5); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/collections/hashmap2.rs: -------------------------------------------------------------------------------- 1 | // hashmap2.rs 2 | 3 | // A basket of fruits in the form of a hash map is given. The key 4 | // represents the name of the fruit and the value represents how many 5 | // of that particular fruit is in the basket. You have to put *MORE 6 | // THAN 11* fruits in the basket. Three types of fruits - Apple (4), 7 | // Mango (2) and Lychee (5) are already given in the basket. You are 8 | // not allowed to insert any more of these fruits! 9 | // 10 | // Make me pass the tests! 11 | // 12 | // Execute the command `rustlings hint hashmap2` if you need 13 | // hints. 14 | 15 | // I AM NOT DONE 16 | 17 | use std::collections::HashMap; 18 | 19 | #[derive(Hash, PartialEq, Eq)] 20 | enum Fruit { 21 | Apple, 22 | Banana, 23 | Mango, 24 | Lychee, 25 | Pineapple, 26 | } 27 | 28 | fn fruit_basket(basket: &mut HashMap) { 29 | let fruit_kinds = vec![ 30 | Fruit::Apple, 31 | Fruit::Banana, 32 | Fruit::Mango, 33 | Fruit::Lychee, 34 | Fruit::Pineapple, 35 | ]; 36 | 37 | for fruit in fruit_kinds { 38 | // TODO: Put new fruits if not already present. Note that you 39 | // are not allowed to put any type of fruit that's already 40 | // present! 41 | } 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use super::*; 47 | 48 | fn get_fruit_basket() -> HashMap { 49 | let mut basket = HashMap::::new(); 50 | basket.insert(Fruit::Apple, 4); 51 | basket.insert(Fruit::Mango, 2); 52 | basket.insert(Fruit::Lychee, 5); 53 | 54 | basket 55 | } 56 | 57 | #[test] 58 | fn test_given_fruits_are_not_modified() { 59 | let mut basket = get_fruit_basket(); 60 | fruit_basket(&mut basket); 61 | assert_eq!(*basket.get(&Fruit::Apple).unwrap(), 4); 62 | assert_eq!(*basket.get(&Fruit::Mango).unwrap(), 2); 63 | assert_eq!(*basket.get(&Fruit::Lychee).unwrap(), 5); 64 | } 65 | 66 | #[test] 67 | fn at_least_five_types_of_fruits() { 68 | let mut basket = get_fruit_basket(); 69 | fruit_basket(&mut basket); 70 | let count_fruit_kinds = basket.len(); 71 | assert!(count_fruit_kinds >= 5); 72 | } 73 | 74 | #[test] 75 | fn greater_than_eleven_fruits() { 76 | let mut basket = get_fruit_basket(); 77 | fruit_basket(&mut basket); 78 | let count = basket.values().sum::(); 79 | assert!(count > 11); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/collections/vec1.rs: -------------------------------------------------------------------------------- 1 | // vec1.rs 2 | // Your task is to create a `Vec` which holds the exact same elements 3 | // as in the array `a`. 4 | // Make me compile and pass the test! 5 | // Execute the command `rustlings hint vec1` if you need hints. 6 | 7 | // I AM NOT DONE 8 | 9 | fn array_and_vec() -> ([i32; 4], Vec) { 10 | let a = [10, 20, 30, 40]; // a plain array 11 | let v = // TODO: declare your vector here with the macro for vectors 12 | 13 | (a, v) 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn test_array_and_vec_similarity() { 22 | let (a, v) = array_and_vec(); 23 | assert_eq!(a, v[..]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/collections/vec2.rs: -------------------------------------------------------------------------------- 1 | // vec2.rs 2 | // A Vec of even numbers is given. Your task is to complete the loop 3 | // so that each number in the Vec is multiplied by 2. 4 | // 5 | // Make me pass the test! 6 | // 7 | // Execute the command `rustlings hint vec2` if you need 8 | // hints. 9 | 10 | // I AM NOT DONE 11 | 12 | fn vec_loop(mut v: Vec) -> Vec { 13 | for i in v.iter_mut() { 14 | // TODO: Fill this up so that each element in the Vec `v` is 15 | // multiplied by 2. 16 | } 17 | 18 | // At this point, `v` should be equal to [4, 8, 12, 16, 20]. 19 | v 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use super::*; 25 | 26 | #[test] 27 | fn test_vec_loop() { 28 | let v: Vec = (1..).filter(|x| x % 2 == 0).take(5).collect(); 29 | let ans = vec_loop(v.clone()); 30 | 31 | assert_eq!(ans, v.iter().map(|x| x * 2).collect::>()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/conversions/README.md: -------------------------------------------------------------------------------- 1 | # Type conversions 2 | 3 | Rust offers a multitude of ways to convert a value of a given type into another type. 4 | 5 | The simplest form of type conversion is a type cast expression. It is denoted with the binary operator `as`. For instance, `println!("{}", 1 + 1.0);` would not compile, since `1` is an integer while `1.0` is a float. However, `println!("{}", 1 as f32 + 1.0)` should compile. The exercise [`using_as`](using_as.rs) tries to cover this. 6 | 7 | Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module. 8 | The traits are the following: 9 | - `From` and `Into` covered in [`from_into`](from_into.rs) 10 | - `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs) 11 | - `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs) 12 | 13 | Furthermore, the `std::str` module offers a trait called [`FromStr`](https://doc.rust-lang.org/std/str/trait.FromStr.html) which helps with converting strings into target types via the `parse` method on strings. If properly implemented for a given type `Person`, then `let p: Person = "Mark,20".parse().unwrap()` should both compile and run without panicking. 14 | 15 | These should be the main ways ***within the standard library*** to convert data into your desired types. 16 | 17 | ## Further information 18 | 19 | These are not directly covered in the book, but the standard library has a great documentation for it. 20 | - [conversions](https://doc.rust-lang.org/std/convert/index.html) 21 | - [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html) -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/conversions/as_ref_mut.rs: -------------------------------------------------------------------------------- 1 | // AsRef and AsMut allow for cheap reference-to-reference conversions. 2 | // Read more about them at https://doc.rust-lang.org/std/convert/trait.AsRef.html 3 | // and https://doc.rust-lang.org/std/convert/trait.AsMut.html, respectively. 4 | 5 | // I AM NOT DONE 6 | 7 | // Obtain the number of bytes (not characters) in the given argument 8 | // Add the AsRef trait appropriately as a trait bound 9 | fn byte_counter(arg: T) -> usize { 10 | arg.as_ref().as_bytes().len() 11 | } 12 | 13 | // Obtain the number of characters (not bytes) in the given argument 14 | // Add the AsRef trait appropriately as a trait bound 15 | fn char_counter(arg: T) -> usize { 16 | arg.as_ref().chars().count() 17 | } 18 | 19 | fn main() { 20 | let s = "Café au lait"; 21 | println!("{}", char_counter(s)); 22 | println!("{}", byte_counter(s)); 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | #[test] 30 | fn different_counts() { 31 | let s = "Café au lait"; 32 | assert_ne!(char_counter(s), byte_counter(s)); 33 | } 34 | 35 | #[test] 36 | fn same_counts() { 37 | let s = "Cafe au lait"; 38 | assert_eq!(char_counter(s), byte_counter(s)); 39 | } 40 | 41 | #[test] 42 | fn different_counts_using_string() { 43 | let s = String::from("Café au lait"); 44 | assert_ne!(char_counter(s.clone()), byte_counter(s)); 45 | } 46 | 47 | #[test] 48 | fn same_counts_using_string() { 49 | let s = String::from("Cafe au lait"); 50 | assert_eq!(char_counter(s.clone()), byte_counter(s)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/conversions/from_into.rs: -------------------------------------------------------------------------------- 1 | // The From trait is used for value-to-value conversions. 2 | // If From is implemented correctly for a type, the Into trait should work conversely. 3 | // You can read more about it at https://doc.rust-lang.org/std/convert/trait.From.html 4 | #[derive(Debug)] 5 | struct Person { 6 | name: String, 7 | age: usize, 8 | } 9 | 10 | // We implement the Default trait to use it as a fallback 11 | // when the provided string is not convertible into a Person object 12 | impl Default for Person { 13 | fn default() -> Person { 14 | Person { 15 | name: String::from("John"), 16 | age: 30, 17 | } 18 | } 19 | } 20 | 21 | // Your task is to complete this implementation 22 | // in order for the line `let p = Person::from("Mark,20")` to compile 23 | // Please note that you'll need to parse the age component into a `usize` 24 | // with something like `"4".parse::()`. The outcome of this needs to 25 | // be handled appropriately. 26 | // 27 | // Steps: 28 | // 1. If the length of the provided string is 0, then return the default of Person 29 | // 2. Split the given string on the commas present in it 30 | // 3. Extract the first element from the split operation and use it as the name 31 | // 4. If the name is empty, then return the default of Person 32 | // 5. Extract the other element from the split operation and parse it into a `usize` as the age 33 | // If while parsing the age, something goes wrong, then return the default of Person 34 | // Otherwise, then return an instantiated Person object with the results 35 | 36 | // I AM NOT DONE 37 | 38 | impl From<&str> for Person { 39 | fn from(s: &str) -> Person { 40 | } 41 | } 42 | 43 | fn main() { 44 | // Use the `from` function 45 | let p1 = Person::from("Mark,20"); 46 | // Since From is implemented for Person, we should be able to use Into 47 | let p2: Person = "Gerald,70".into(); 48 | println!("{:?}", p1); 49 | println!("{:?}", p2); 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | #[test] 56 | fn test_default() { 57 | // Test that the default person is 30 year old John 58 | let dp = Person::default(); 59 | assert_eq!(dp.name, "John"); 60 | assert_eq!(dp.age, 30); 61 | } 62 | #[test] 63 | fn test_bad_convert() { 64 | // Test that John is returned when bad string is provided 65 | let p = Person::from(""); 66 | assert_eq!(p.name, "John"); 67 | assert_eq!(p.age, 30); 68 | } 69 | #[test] 70 | fn test_good_convert() { 71 | // Test that "Mark,20" works 72 | let p = Person::from("Mark,20"); 73 | assert_eq!(p.name, "Mark"); 74 | assert_eq!(p.age, 20); 75 | } 76 | #[test] 77 | fn test_bad_age() { 78 | // Test that "Mark,twenty" will return the default person due to an error in parsing age 79 | let p = Person::from("Mark,twenty"); 80 | assert_eq!(p.name, "John"); 81 | assert_eq!(p.age, 30); 82 | } 83 | 84 | #[test] 85 | fn test_missing_comma_and_age() { 86 | let p: Person = Person::from("Mark"); 87 | assert_eq!(p.name, "John"); 88 | assert_eq!(p.age, 30); 89 | } 90 | 91 | #[test] 92 | fn test_missing_age() { 93 | let p: Person = Person::from("Mark,"); 94 | assert_eq!(p.name, "John"); 95 | assert_eq!(p.age, 30); 96 | } 97 | 98 | #[test] 99 | fn test_missing_name() { 100 | let p: Person = Person::from(",1"); 101 | assert_eq!(p.name, "John"); 102 | assert_eq!(p.age, 30); 103 | } 104 | 105 | #[test] 106 | fn test_missing_name_and_age() { 107 | let p: Person = Person::from(","); 108 | assert_eq!(p.name, "John"); 109 | assert_eq!(p.age, 30); 110 | } 111 | 112 | #[test] 113 | fn test_missing_name_and_invalid_age() { 114 | let p: Person = Person::from(",one"); 115 | assert_eq!(p.name, "John"); 116 | assert_eq!(p.age, 30); 117 | } 118 | 119 | #[test] 120 | fn test_trailing_comma() { 121 | let p: Person = Person::from("Mike,32,"); 122 | assert_eq!(p.name, "John"); 123 | assert_eq!(p.age, 30); 124 | } 125 | 126 | #[test] 127 | fn test_trailing_comma_and_some_string() { 128 | let p: Person = Person::from("Mike,32,man"); 129 | assert_eq!(p.name, "John"); 130 | assert_eq!(p.age, 30); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/conversions/from_str.rs: -------------------------------------------------------------------------------- 1 | // from_str.rs 2 | // This is similar to from_into.rs, but this time we'll implement `FromStr` 3 | // and return errors instead of falling back to a default value. 4 | // Additionally, upon implementing FromStr, you can use the `parse` method 5 | // on strings to generate an object of the implementor type. 6 | // You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html 7 | use std::num::ParseIntError; 8 | use std::str::FromStr; 9 | 10 | #[derive(Debug, PartialEq)] 11 | struct Person { 12 | name: String, 13 | age: usize, 14 | } 15 | 16 | // We will use this error type for the `FromStr` implementation. 17 | #[derive(Debug, PartialEq)] 18 | enum ParsePersonError { 19 | // Empty input string 20 | Empty, 21 | // Incorrect number of fields 22 | BadLen, 23 | // Empty name field 24 | NoName, 25 | // Wrapped error from parse::() 26 | ParseInt(ParseIntError), 27 | } 28 | 29 | // I AM NOT DONE 30 | 31 | // Steps: 32 | // 1. If the length of the provided string is 0, an error should be returned 33 | // 2. Split the given string on the commas present in it 34 | // 3. Only 2 elements should be returned from the split, otherwise return an error 35 | // 4. Extract the first element from the split operation and use it as the name 36 | // 5. Extract the other element from the split operation and parse it into a `usize` as the age 37 | // with something like `"4".parse::()` 38 | // 6. If while extracting the name and the age something goes wrong, an error should be returned 39 | // If everything goes well, then return a Result of a Person object 40 | 41 | impl FromStr for Person { 42 | type Err = ParsePersonError; 43 | fn from_str(s: &str) -> Result { 44 | } 45 | } 46 | 47 | fn main() { 48 | let p = "Mark,20".parse::().unwrap(); 49 | println!("{:?}", p); 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | 56 | #[test] 57 | fn empty_input() { 58 | assert_eq!("".parse::(), Err(ParsePersonError::Empty)); 59 | } 60 | #[test] 61 | fn good_input() { 62 | let p = "John,32".parse::(); 63 | assert!(p.is_ok()); 64 | let p = p.unwrap(); 65 | assert_eq!(p.name, "John"); 66 | assert_eq!(p.age, 32); 67 | } 68 | #[test] 69 | fn missing_age() { 70 | assert!(matches!( 71 | "John,".parse::(), 72 | Err(ParsePersonError::ParseInt(_)) 73 | )); 74 | } 75 | 76 | #[test] 77 | fn invalid_age() { 78 | assert!(matches!( 79 | "John,twenty".parse::(), 80 | Err(ParsePersonError::ParseInt(_)) 81 | )); 82 | } 83 | 84 | #[test] 85 | fn missing_comma_and_age() { 86 | assert_eq!("John".parse::(), Err(ParsePersonError::BadLen)); 87 | } 88 | 89 | #[test] 90 | fn missing_name() { 91 | assert_eq!(",1".parse::(), Err(ParsePersonError::NoName)); 92 | } 93 | 94 | #[test] 95 | fn missing_name_and_age() { 96 | assert!(matches!( 97 | ",".parse::(), 98 | Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) 99 | )); 100 | } 101 | 102 | #[test] 103 | fn missing_name_and_invalid_age() { 104 | assert!(matches!( 105 | ",one".parse::(), 106 | Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_)) 107 | )); 108 | } 109 | 110 | #[test] 111 | fn trailing_comma() { 112 | assert_eq!("John,32,".parse::(), Err(ParsePersonError::BadLen)); 113 | } 114 | 115 | #[test] 116 | fn trailing_comma_and_some_string() { 117 | assert_eq!( 118 | "John,32,man".parse::(), 119 | Err(ParsePersonError::BadLen) 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/conversions/try_from_into.rs: -------------------------------------------------------------------------------- 1 | // try_from_into.rs 2 | // TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances. 3 | // Basically, this is the same as From. The main difference is that this should return a Result type 4 | // instead of the target type itself. 5 | // You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html 6 | use std::convert::{TryFrom, TryInto}; 7 | 8 | #[derive(Debug, PartialEq)] 9 | struct Color { 10 | red: u8, 11 | green: u8, 12 | blue: u8, 13 | } 14 | 15 | // We will use this error type for these `TryFrom` conversions. 16 | #[derive(Debug, PartialEq)] 17 | enum IntoColorError { 18 | // Incorrect length of slice 19 | BadLen, 20 | // Integer conversion error 21 | IntConversion, 22 | } 23 | 24 | // I AM NOT DONE 25 | 26 | // Your task is to complete this implementation 27 | // and return an Ok result of inner type Color. 28 | // You need to create an implementation for a tuple of three integers, 29 | // an array of three integers, and a slice of integers. 30 | // 31 | // Note that the implementation for tuple and array will be checked at compile time, 32 | // but the slice implementation needs to check the slice length! 33 | // Also note that correct RGB color values must be integers in the 0..=255 range. 34 | 35 | // Tuple implementation 36 | impl TryFrom<(i16, i16, i16)> for Color { 37 | type Error = IntoColorError; 38 | fn try_from(tuple: (i16, i16, i16)) -> Result { 39 | } 40 | } 41 | 42 | // Array implementation 43 | impl TryFrom<[i16; 3]> for Color { 44 | type Error = IntoColorError; 45 | fn try_from(arr: [i16; 3]) -> Result { 46 | } 47 | } 48 | 49 | // Slice implementation 50 | impl TryFrom<&[i16]> for Color { 51 | type Error = IntoColorError; 52 | fn try_from(slice: &[i16]) -> Result { 53 | } 54 | } 55 | 56 | fn main() { 57 | // Use the `from` function 58 | let c1 = Color::try_from((183, 65, 14)); 59 | println!("{:?}", c1); 60 | 61 | // Since TryFrom is implemented for Color, we should be able to use TryInto 62 | let c2: Result = [183, 65, 14].try_into(); 63 | println!("{:?}", c2); 64 | 65 | let v = vec![183, 65, 14]; 66 | // With slice we should use `try_from` function 67 | let c3 = Color::try_from(&v[..]); 68 | println!("{:?}", c3); 69 | // or take slice within round brackets and use TryInto 70 | let c4: Result = (&v[..]).try_into(); 71 | println!("{:?}", c4); 72 | } 73 | 74 | #[cfg(test)] 75 | mod tests { 76 | use super::*; 77 | 78 | #[test] 79 | fn test_tuple_out_of_range_positive() { 80 | assert_eq!( 81 | Color::try_from((256, 1000, 10000)), 82 | Err(IntoColorError::IntConversion) 83 | ); 84 | } 85 | #[test] 86 | fn test_tuple_out_of_range_negative() { 87 | assert_eq!( 88 | Color::try_from((-1, -10, -256)), 89 | Err(IntoColorError::IntConversion) 90 | ); 91 | } 92 | #[test] 93 | fn test_tuple_sum() { 94 | assert_eq!( 95 | Color::try_from((-1, 255, 255)), 96 | Err(IntoColorError::IntConversion) 97 | ); 98 | } 99 | #[test] 100 | fn test_tuple_correct() { 101 | let c: Result = (183, 65, 14).try_into(); 102 | assert!(c.is_ok()); 103 | assert_eq!( 104 | c.unwrap(), 105 | Color { 106 | red: 183, 107 | green: 65, 108 | blue: 14 109 | } 110 | ); 111 | } 112 | #[test] 113 | fn test_array_out_of_range_positive() { 114 | let c: Result = [1000, 10000, 256].try_into(); 115 | assert_eq!(c, Err(IntoColorError::IntConversion)); 116 | } 117 | #[test] 118 | fn test_array_out_of_range_negative() { 119 | let c: Result = [-10, -256, -1].try_into(); 120 | assert_eq!(c, Err(IntoColorError::IntConversion)); 121 | } 122 | #[test] 123 | fn test_array_sum() { 124 | let c: Result = [-1, 255, 255].try_into(); 125 | assert_eq!(c, Err(IntoColorError::IntConversion)); 126 | } 127 | #[test] 128 | fn test_array_correct() { 129 | let c: Result = [183, 65, 14].try_into(); 130 | assert!(c.is_ok()); 131 | assert_eq!( 132 | c.unwrap(), 133 | Color { 134 | red: 183, 135 | green: 65, 136 | blue: 14 137 | } 138 | ); 139 | } 140 | #[test] 141 | fn test_slice_out_of_range_positive() { 142 | let arr = [10000, 256, 1000]; 143 | assert_eq!( 144 | Color::try_from(&arr[..]), 145 | Err(IntoColorError::IntConversion) 146 | ); 147 | } 148 | #[test] 149 | fn test_slice_out_of_range_negative() { 150 | let arr = [-256, -1, -10]; 151 | assert_eq!( 152 | Color::try_from(&arr[..]), 153 | Err(IntoColorError::IntConversion) 154 | ); 155 | } 156 | #[test] 157 | fn test_slice_sum() { 158 | let arr = [-1, 255, 255]; 159 | assert_eq!( 160 | Color::try_from(&arr[..]), 161 | Err(IntoColorError::IntConversion) 162 | ); 163 | } 164 | #[test] 165 | fn test_slice_correct() { 166 | let v = vec![183, 65, 14]; 167 | let c: Result = Color::try_from(&v[..]); 168 | assert!(c.is_ok()); 169 | assert_eq!( 170 | c.unwrap(), 171 | Color { 172 | red: 183, 173 | green: 65, 174 | blue: 14 175 | } 176 | ); 177 | } 178 | #[test] 179 | fn test_slice_excess_length() { 180 | let v = vec![0, 0, 0, 0]; 181 | assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); 182 | } 183 | #[test] 184 | fn test_slice_insufficient_length() { 185 | let v = vec![0, 0]; 186 | assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen)); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/conversions/using_as.rs: -------------------------------------------------------------------------------- 1 | // Type casting in Rust is done via the usage of the `as` operator. 2 | // Please note that the `as` operator is not only used when type casting. 3 | // It also helps with renaming imports. 4 | // 5 | // The goal is to make sure that the division does not fail to compile 6 | // and returns the proper type. 7 | 8 | // I AM NOT DONE 9 | 10 | fn average(values: &[f64]) -> f64 { 11 | let total = values.iter().fold(0.0, |a, b| a + b); 12 | total / values.len() 13 | } 14 | 15 | fn main() { 16 | let values = [3.5, 0.3, 13.0, 11.7]; 17 | println!("{}", average(&values)); 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | 24 | #[test] 25 | fn returns_proper_type_and_value() { 26 | assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/enums/README.md: -------------------------------------------------------------------------------- 1 | # Enums 2 | 3 | Rust allows you to define types called "enums" which enumerate possible values. 4 | Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell. 5 | Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration. 6 | 7 | ## Further information 8 | 9 | - [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html) 10 | - [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html) 11 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/enums/enums1.rs: -------------------------------------------------------------------------------- 1 | // enums1.rs 2 | // Make me compile! Execute `rustlings hint enums1` for hints! 3 | 4 | // I AM NOT DONE 5 | 6 | #[derive(Debug)] 7 | enum Message { 8 | // TODO: define a few types of messages as used below 9 | } 10 | 11 | fn main() { 12 | println!("{:?}", Message::Quit); 13 | println!("{:?}", Message::Echo); 14 | println!("{:?}", Message::Move); 15 | println!("{:?}", Message::ChangeColor); 16 | } 17 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/enums/enums2.rs: -------------------------------------------------------------------------------- 1 | // enums2.rs 2 | // Make me compile! Execute `rustlings hint enums2` for hints! 3 | 4 | // I AM NOT DONE 5 | 6 | #[derive(Debug)] 7 | enum Message { 8 | // TODO: define the different variants used below 9 | } 10 | 11 | impl Message { 12 | fn call(&self) { 13 | println!("{:?}", &self); 14 | } 15 | } 16 | 17 | fn main() { 18 | let messages = [ 19 | Message::Move { x: 10, y: 30 }, 20 | Message::Echo(String::from("hello world")), 21 | Message::ChangeColor(200, 255, 255), 22 | Message::Quit, 23 | ]; 24 | 25 | for message in &messages { 26 | message.call(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/enums/enums3.rs: -------------------------------------------------------------------------------- 1 | // enums3.rs 2 | // Address all the TODOs to make the tests pass! 3 | 4 | // I AM NOT DONE 5 | 6 | enum Message { 7 | // TODO: implement the message variant types based on their usage below 8 | } 9 | 10 | struct Point { 11 | x: u8, 12 | y: u8, 13 | } 14 | 15 | struct State { 16 | color: (u8, u8, u8), 17 | position: Point, 18 | quit: bool, 19 | } 20 | 21 | impl State { 22 | fn change_color(&mut self, color: (u8, u8, u8)) { 23 | self.color = color; 24 | } 25 | 26 | fn quit(&mut self) { 27 | self.quit = true; 28 | } 29 | 30 | fn echo(&self, s: String) { 31 | println!("{}", s); 32 | } 33 | 34 | fn move_position(&mut self, p: Point) { 35 | self.position = p; 36 | } 37 | 38 | fn process(&mut self, message: Message) { 39 | // TODO: create a match expression to process the different message variants 40 | } 41 | } 42 | 43 | #[cfg(test)] 44 | mod tests { 45 | use super::*; 46 | 47 | #[test] 48 | fn test_match_message_call() { 49 | let mut state = State { 50 | quit: false, 51 | position: Point { x: 0, y: 0 }, 52 | color: (0, 0, 0), 53 | }; 54 | state.process(Message::ChangeColor((255, 0, 255))); 55 | state.process(Message::Echo(String::from("hello world"))); 56 | state.process(Message::Move(Point { x: 10, y: 15 })); 57 | state.process(Message::Quit); 58 | 59 | assert_eq!(state.color, (255, 0, 255)); 60 | assert_eq!(state.position.x, 10); 61 | assert_eq!(state.position.y, 15); 62 | assert_eq!(state.quit, true); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/README.md: -------------------------------------------------------------------------------- 1 | # Error handling 2 | Most errors aren’t serious enough to require the program to stop entirely. 3 | Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. 4 | For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process. 5 | 6 | ## Further information 7 | 8 | - [Error Handling](https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html) 9 | - [Generics](https://doc.rust-lang.org/book/ch10-01-syntax.html) 10 | - [Result](https://doc.rust-lang.org/rust-by-example/error/result.html) 11 | - [Boxing errors](https://doc.rust-lang.org/rust-by-example/error/multiple_error_types/boxing_errors.html) 12 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/errors1.rs: -------------------------------------------------------------------------------- 1 | // errors1.rs 2 | // This function refuses to generate text to be printed on a nametag if 3 | // you pass it an empty string. It'd be nicer if it explained what the problem 4 | // was, instead of just sometimes returning `None`. The 2nd test currently 5 | // does not compile or pass, but it illustrates the behavior we would like 6 | // this function to have. 7 | // Execute `rustlings hint errors1` for hints! 8 | 9 | // I AM NOT DONE 10 | 11 | pub fn generate_nametag_text(name: String) -> Option { 12 | if name.len() > 0 { 13 | Some(format!("Hi! My name is {}", name)) 14 | } else { 15 | // Empty names aren't allowed. 16 | None 17 | } 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | 24 | // This test passes initially if you comment out the 2nd test. 25 | // You'll need to update what this test expects when you change 26 | // the function under test! 27 | #[test] 28 | fn generates_nametag_text_for_a_nonempty_name() { 29 | assert_eq!( 30 | generate_nametag_text("Beyoncé".into()), 31 | Some("Hi! My name is Beyoncé".into()) 32 | ); 33 | } 34 | 35 | #[test] 36 | fn explains_why_generating_nametag_text_fails() { 37 | assert_eq!( 38 | generate_nametag_text("".into()), 39 | Err("`name` was empty; it must be nonempty.".into()) 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/errors2.rs: -------------------------------------------------------------------------------- 1 | // errors2.rs 2 | // Say we're writing a game where you can buy items with tokens. All items cost 3 | // 5 tokens, and whenever you purchase items there is a processing fee of 1 4 | // token. A player of the game will type in how many items they want to buy, 5 | // and the `total_cost` function will calculate the total number of tokens. 6 | // Since the player typed in the quantity, though, we get it as a string-- and 7 | // they might have typed anything, not just numbers! 8 | 9 | // Right now, this function isn't handling the error case at all (and isn't 10 | // handling the success case properly either). What we want to do is: 11 | // if we call the `parse` function on a string that is not a number, that 12 | // function will return a `ParseIntError`, and in that case, we want to 13 | // immediately return that error from our function and not try to multiply 14 | // and add. 15 | 16 | // There are at least two ways to implement this that are both correct-- but 17 | // one is a lot shorter! Execute `rustlings hint errors2` for hints to both ways. 18 | 19 | // I AM NOT DONE 20 | 21 | use std::num::ParseIntError; 22 | 23 | pub fn total_cost(item_quantity: &str) -> Result { 24 | let processing_fee = 1; 25 | let cost_per_item = 5; 26 | let qty = item_quantity.parse::(); 27 | 28 | Ok(qty * cost_per_item + processing_fee) 29 | } 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | use super::*; 34 | 35 | #[test] 36 | fn item_quantity_is_a_valid_number() { 37 | assert_eq!(total_cost("34"), Ok(171)); 38 | } 39 | 40 | #[test] 41 | fn item_quantity_is_an_invalid_number() { 42 | assert_eq!( 43 | total_cost("beep boop").unwrap_err().to_string(), 44 | "invalid digit found in string" 45 | ); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/errors3.rs: -------------------------------------------------------------------------------- 1 | // errors3.rs 2 | // This is a program that is trying to use a completed version of the 3 | // `total_cost` function from the previous exercise. It's not working though! 4 | // Why not? What should we do to fix it? 5 | // Execute `rustlings hint errors3` for hints! 6 | 7 | // I AM NOT DONE 8 | 9 | use std::num::ParseIntError; 10 | 11 | fn main() { 12 | let mut tokens = 100; 13 | let pretend_user_input = "8"; 14 | 15 | let cost = total_cost(pretend_user_input)?; 16 | 17 | if cost > tokens { 18 | println!("You can't afford that many!"); 19 | } else { 20 | tokens -= cost; 21 | println!("You now have {} tokens.", tokens); 22 | } 23 | } 24 | 25 | pub fn total_cost(item_quantity: &str) -> Result { 26 | let processing_fee = 1; 27 | let cost_per_item = 5; 28 | let qty = item_quantity.parse::()?; 29 | 30 | Ok(qty * cost_per_item + processing_fee) 31 | } 32 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/errors4.rs: -------------------------------------------------------------------------------- 1 | // errors4.rs 2 | // Make this test pass! Execute `rustlings hint errors4` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | #[derive(PartialEq, Debug)] 7 | struct PositiveNonzeroInteger(u64); 8 | 9 | #[derive(PartialEq, Debug)] 10 | enum CreationError { 11 | Negative, 12 | Zero, 13 | } 14 | 15 | impl PositiveNonzeroInteger { 16 | fn new(value: i64) -> Result { 17 | Ok(PositiveNonzeroInteger(value as u64)) 18 | } 19 | } 20 | 21 | #[test] 22 | fn test_creation() { 23 | assert!(PositiveNonzeroInteger::new(10).is_ok()); 24 | assert_eq!( 25 | Err(CreationError::Negative), 26 | PositiveNonzeroInteger::new(-10) 27 | ); 28 | assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0)); 29 | } 30 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/errors5.rs: -------------------------------------------------------------------------------- 1 | // errors5.rs 2 | 3 | // This program uses a completed version of the code from errors4. 4 | // It won't compile right now! Why? 5 | // Execute `rustlings hint errors5` for hints! 6 | 7 | // I AM NOT DONE 8 | 9 | use std::error; 10 | use std::fmt; 11 | use std::num::ParseIntError; 12 | 13 | // TODO: update the return type of `main()` to make this compile. 14 | fn main() -> Result<(), ParseIntError> { 15 | let pretend_user_input = "42"; 16 | let x: i64 = pretend_user_input.parse()?; 17 | println!("output={:?}", PositiveNonzeroInteger::new(x)?); 18 | Ok(()) 19 | } 20 | 21 | // Don't change anything below this line. 22 | 23 | #[derive(PartialEq, Debug)] 24 | struct PositiveNonzeroInteger(u64); 25 | 26 | #[derive(PartialEq, Debug)] 27 | enum CreationError { 28 | Negative, 29 | Zero, 30 | } 31 | 32 | impl PositiveNonzeroInteger { 33 | fn new(value: i64) -> Result { 34 | match value { 35 | x if x < 0 => Err(CreationError::Negative), 36 | x if x == 0 => Err(CreationError::Zero), 37 | x => Ok(PositiveNonzeroInteger(x as u64)) 38 | } 39 | } 40 | } 41 | 42 | // This is required so that `CreationError` can implement `error::Error`. 43 | impl fmt::Display for CreationError { 44 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 | let description = match *self { 46 | CreationError::Negative => "number is negative", 47 | CreationError::Zero => "number is zero", 48 | }; 49 | f.write_str(description) 50 | } 51 | } 52 | 53 | impl error::Error for CreationError {} 54 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/error_handling/errors6.rs: -------------------------------------------------------------------------------- 1 | // errors6.rs 2 | 3 | // Using catch-all error types like `Box` isn't recommended 4 | // for library code, where callers might want to make decisions based on the 5 | // error content, instead of printing it out or propagating it further. Here, 6 | // we define a custom error type to make it possible for callers to decide 7 | // what to do next when our function returns an error. 8 | 9 | // Make these tests pass! Execute `rustlings hint errors6` for hints :) 10 | 11 | // I AM NOT DONE 12 | 13 | use std::num::ParseIntError; 14 | 15 | // This is a custom error type that we will be using in `parse_pos_nonzero()`. 16 | #[derive(PartialEq, Debug)] 17 | enum ParsePosNonzeroError { 18 | Creation(CreationError), 19 | ParseInt(ParseIntError) 20 | } 21 | 22 | impl ParsePosNonzeroError { 23 | fn from_creation(err: CreationError) -> ParsePosNonzeroError { 24 | ParsePosNonzeroError::Creation(err) 25 | } 26 | // TODO: add another error conversion function here. 27 | } 28 | 29 | fn parse_pos_nonzero(s: &str) 30 | -> Result 31 | { 32 | // TODO: change this to return an appropriate error instead of panicking 33 | // when `parse()` returns an error. 34 | let x: i64 = s.parse().unwrap(); 35 | PositiveNonzeroInteger::new(x) 36 | .map_err(ParsePosNonzeroError::from_creation) 37 | } 38 | 39 | // Don't change anything below this line. 40 | 41 | #[derive(PartialEq, Debug)] 42 | struct PositiveNonzeroInteger(u64); 43 | 44 | #[derive(PartialEq, Debug)] 45 | enum CreationError { 46 | Negative, 47 | Zero, 48 | } 49 | 50 | impl PositiveNonzeroInteger { 51 | fn new(value: i64) -> Result { 52 | match value { 53 | x if x < 0 => Err(CreationError::Negative), 54 | x if x == 0 => Err(CreationError::Zero), 55 | x => Ok(PositiveNonzeroInteger(x as u64)) 56 | } 57 | } 58 | } 59 | 60 | #[cfg(test)] 61 | mod test { 62 | use super::*; 63 | 64 | #[test] 65 | fn test_parse_error() { 66 | // We can't construct a ParseIntError, so we have to pattern match. 67 | assert!(matches!( 68 | parse_pos_nonzero("not a number"), 69 | Err(ParsePosNonzeroError::ParseInt(_)) 70 | )); 71 | } 72 | 73 | #[test] 74 | fn test_negative() { 75 | assert_eq!( 76 | parse_pos_nonzero("-555"), 77 | Err(ParsePosNonzeroError::Creation(CreationError::Negative)) 78 | ); 79 | } 80 | 81 | #[test] 82 | fn test_zero() { 83 | assert_eq!( 84 | parse_pos_nonzero("0"), 85 | Err(ParsePosNonzeroError::Creation(CreationError::Zero)) 86 | ); 87 | } 88 | 89 | #[test] 90 | fn test_positive() { 91 | let x = PositiveNonzeroInteger::new(42); 92 | assert!(x.is_ok()); 93 | assert_eq!(parse_pos_nonzero("42"), Ok(x.unwrap())); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/functions/README.md: -------------------------------------------------------------------------------- 1 | # Functions 2 | 3 | Here, you'll learn how to write functions and how Rust's compiler can trace things way back. 4 | 5 | ## Further information 6 | 7 | - [How Functions Work](https://doc.rust-lang.org/book/ch03-03-how-functions-work.html) 8 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/functions/functions1.rs: -------------------------------------------------------------------------------- 1 | // functions1.rs 2 | // Make me compile! Execute `rustlings hint functions1` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | call_me(); 8 | } 9 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/functions/functions2.rs: -------------------------------------------------------------------------------- 1 | // functions2.rs 2 | // Make me compile! Execute `rustlings hint functions2` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | call_me(3); 8 | } 9 | 10 | fn call_me(num:) { 11 | for i in 0..num { 12 | println!("Ring! Call number {}", i + 1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/functions/functions3.rs: -------------------------------------------------------------------------------- 1 | // functions3.rs 2 | // Make me compile! Execute `rustlings hint functions3` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | call_me(); 8 | } 9 | 10 | fn call_me(num: u32) { 11 | for i in 0..num { 12 | println!("Ring! Call number {}", i + 1); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/functions/functions4.rs: -------------------------------------------------------------------------------- 1 | // functions4.rs 2 | // Make me compile! Execute `rustlings hint functions4` for hints :) 3 | 4 | // This store is having a sale where if the price is an even number, you get 5 | // 10 Rustbucks off, but if it's an odd number, it's 3 Rustbucks off. 6 | 7 | // I AM NOT DONE 8 | 9 | fn main() { 10 | let original_price = 51; 11 | println!("Your sale price is {}", sale_price(original_price)); 12 | } 13 | 14 | fn sale_price(price: i32) -> { 15 | if is_even(price) { 16 | price - 10 17 | } else { 18 | price - 3 19 | } 20 | } 21 | 22 | fn is_even(num: i32) -> bool { 23 | num % 2 == 0 24 | } 25 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/functions/functions5.rs: -------------------------------------------------------------------------------- 1 | // functions5.rs 2 | // Make me compile! Execute `rustlings hint functions5` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let answer = square(3); 8 | println!("The answer is {}", answer); 9 | } 10 | 11 | fn square(num: i32) -> i32 { 12 | num * num; 13 | } 14 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/generics/README.md: -------------------------------------------------------------------------------- 1 | # Generics 2 | 3 | Generics is the topic of generalizing types and functionalities to broader cases. 4 | This is extremely useful for reducing code duplication in many ways, but can call for rather involving syntax. 5 | Namely, being generic requires taking great care to specify over which types a generic type is actually considered valid. 6 | The simplest and most common use of generics is for type parameters. 7 | 8 | ## Further information 9 | 10 | - [Generic Data Types](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html) 11 | - [Bounds](https://doc.rust-lang.org/rust-by-example/generics/bounds.html) 12 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/generics/generics1.rs: -------------------------------------------------------------------------------- 1 | // This shopping list program isn't compiling! 2 | // Use your knowledge of generics to fix it. 3 | 4 | // Execute `rustlings hint generics1` for hints! 5 | 6 | // I AM NOT DONE 7 | 8 | fn main() { 9 | let mut shopping_list: Vec = Vec::new(); 10 | shopping_list.push("milk"); 11 | } 12 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/generics/generics2.rs: -------------------------------------------------------------------------------- 1 | // This powerful wrapper provides the ability to store a positive integer value. 2 | // Rewrite it using generics so that it supports wrapping ANY type. 3 | 4 | // Execute `rustlings hint generics2` for hints! 5 | 6 | // I AM NOT DONE 7 | 8 | struct Wrapper { 9 | value: u32, 10 | } 11 | 12 | impl Wrapper { 13 | pub fn new(value: u32) -> Self { 14 | Wrapper { value } 15 | } 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use super::*; 21 | 22 | #[test] 23 | fn store_u32_in_wrapper() { 24 | assert_eq!(Wrapper::new(42).value, 42); 25 | } 26 | 27 | #[test] 28 | fn store_str_in_wrapper() { 29 | assert_eq!(Wrapper::new("Foo").value, "Foo"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/generics/generics3.rs: -------------------------------------------------------------------------------- 1 | // An imaginary magical school has a new report card generation system written in Rust! 2 | // Currently the system only supports creating report cards where the student's grade 3 | // is represented numerically (e.g. 1.0 -> 5.5). 4 | // However, the school also issues alphabetical grades (A+ -> F-) and needs 5 | // to be able to print both types of report card! 6 | 7 | // Make the necessary code changes in the struct ReportCard and the impl block 8 | // to support alphabetical report cards. Change the Grade in the second test to "A+" 9 | // to show that your changes allow alphabetical grades. 10 | 11 | // Execute 'rustlings hint generics3' for hints! 12 | 13 | // I AM NOT DONE 14 | 15 | pub struct ReportCard { 16 | pub grade: f32, 17 | pub student_name: String, 18 | pub student_age: u8, 19 | } 20 | 21 | impl ReportCard { 22 | pub fn print(&self) -> String { 23 | format!("{} ({}) - achieved a grade of {}", 24 | &self.student_name, &self.student_age, &self.grade) 25 | } 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | 32 | #[test] 33 | fn generate_numeric_report_card() { 34 | let report_card = ReportCard { 35 | grade: 2.1, 36 | student_name: "Tom Wriggle".to_string(), 37 | student_age: 12, 38 | }; 39 | assert_eq!( 40 | report_card.print(), 41 | "Tom Wriggle (12) - achieved a grade of 2.1" 42 | ); 43 | } 44 | 45 | #[test] 46 | fn generate_alphabetic_report_card() { 47 | // TODO: Make sure to change the grade here after you finish the exercise. 48 | let report_card = ReportCard { 49 | grade: 2.1, 50 | student_name: "Gary Plotter".to_string(), 51 | student_age: 11, 52 | }; 53 | assert_eq!( 54 | report_card.print(), 55 | "Gary Plotter (11) - achieved a grade of A+" 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/if/README.md: -------------------------------------------------------------------------------- 1 | # If 2 | 3 | `if`, the most basic type of control flow, is what you'll learn here. 4 | 5 | ## Further information 6 | 7 | - [Control Flow - if expressions](https://doc.rust-lang.org/book/ch03-05-control-flow.html#if-expressions) 8 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/if/if1.rs: -------------------------------------------------------------------------------- 1 | // if1.rs 2 | 3 | // I AM NOT DONE 4 | 5 | pub fn bigger(a: i32, b: i32) -> i32 { 6 | // Complete this function to return the bigger number! 7 | // Do not use: 8 | // - another function call 9 | // - additional variables 10 | // Execute `rustlings hint if1` for hints 11 | } 12 | 13 | // Don't mind this for now :) 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn ten_is_bigger_than_eight() { 20 | assert_eq!(10, bigger(10, 8)); 21 | } 22 | 23 | #[test] 24 | fn fortytwo_is_bigger_than_thirtytwo() { 25 | assert_eq!(42, bigger(32, 42)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/if/if2.rs: -------------------------------------------------------------------------------- 1 | // if2.rs 2 | 3 | // Step 1: Make me compile! 4 | // Step 2: Get the bar_for_fuzz and default_to_baz tests passing! 5 | // Execute the command `rustlings hint if2` if you want a hint :) 6 | 7 | // I AM NOT DONE 8 | 9 | pub fn fizz_if_foo(fizzish: &str) -> &str { 10 | if fizzish == "fizz" { 11 | "foo" 12 | } else { 13 | 1 14 | } 15 | } 16 | 17 | // No test changes needed! 18 | #[cfg(test)] 19 | mod tests { 20 | use super::*; 21 | 22 | #[test] 23 | fn foo_for_fizz() { 24 | assert_eq!(fizz_if_foo("fizz"), "foo") 25 | } 26 | 27 | #[test] 28 | fn bar_for_fuzz() { 29 | assert_eq!(fizz_if_foo("fuzz"), "bar") 30 | } 31 | 32 | #[test] 33 | fn default_to_baz() { 34 | assert_eq!(fizz_if_foo("literally anything"), "baz") 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/macros/README.md: -------------------------------------------------------------------------------- 1 | # Macros 2 | 3 | Rust's macro system is very powerful, but also kind of difficult to wrap your 4 | head around. We're not going to teach you how to write your own fully-featured 5 | macros. Instead, we'll show you how to use and create them. 6 | 7 | ## Further information 8 | 9 | - [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) 10 | - [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html) 11 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/macros/macros1.rs: -------------------------------------------------------------------------------- 1 | // macros1.rs 2 | // Make me compile! Execute `rustlings hint macros1` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | macro_rules! my_macro { 7 | () => { 8 | println!("Check out my macro!"); 9 | }; 10 | } 11 | 12 | fn main() { 13 | my_macro(); 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/macros/macros2.rs: -------------------------------------------------------------------------------- 1 | // macros2.rs 2 | // Make me compile! Execute `rustlings hint macros2` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | my_macro!(); 8 | } 9 | 10 | macro_rules! my_macro { 11 | () => { 12 | println!("Check out my macro!"); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/macros/macros3.rs: -------------------------------------------------------------------------------- 1 | // macros3.rs 2 | // Make me compile, without taking the macro out of the module! 3 | // Execute `rustlings hint macros3` for hints :) 4 | 5 | // I AM NOT DONE 6 | 7 | mod macros { 8 | macro_rules! my_macro { 9 | () => { 10 | println!("Check out my macro!"); 11 | }; 12 | } 13 | } 14 | 15 | fn main() { 16 | my_macro!(); 17 | } 18 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/macros/macros4.rs: -------------------------------------------------------------------------------- 1 | // macros4.rs 2 | // Make me compile! Execute `rustlings hint macros4` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | macro_rules! my_macro { 7 | () => { 8 | println!("Check out my macro!"); 9 | } 10 | ($val:expr) => { 11 | println!("Look at this other macro: {}", $val); 12 | } 13 | } 14 | 15 | fn main() { 16 | my_macro!(); 17 | my_macro!(7777); 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/modules/README.md: -------------------------------------------------------------------------------- 1 | # Modules 2 | 3 | In this section we'll give you an introduction to Rust's module system. 4 | 5 | ## Further information 6 | 7 | - [The Module System](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) 8 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/modules/modules1.rs: -------------------------------------------------------------------------------- 1 | // modules1.rs 2 | // Make me compile! Execute `rustlings hint modules1` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | mod sausage_factory { 7 | // Don't let anybody outside of this module see this! 8 | fn get_secret_recipe() -> String { 9 | String::from("Ginger") 10 | } 11 | 12 | fn make_sausage() { 13 | get_secret_recipe(); 14 | println!("sausage!"); 15 | } 16 | } 17 | 18 | fn main() { 19 | sausage_factory::make_sausage(); 20 | } 21 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/modules/modules2.rs: -------------------------------------------------------------------------------- 1 | // modules2.rs 2 | // You can bring module paths into scopes and provide new names for them with the 3 | // 'use' and 'as' keywords. Fix these 'use' statements to make the code compile. 4 | // Make me compile! Execute `rustlings hint modules2` for hints :) 5 | 6 | // I AM NOT DONE 7 | 8 | mod delicious_snacks { 9 | 10 | // TODO: Fix these use statements 11 | use self::fruits::PEAR as ??? 12 | use self::veggies::CUCUMBER as ??? 13 | 14 | mod fruits { 15 | pub const PEAR: &'static str = "Pear"; 16 | pub const APPLE: &'static str = "Apple"; 17 | } 18 | 19 | mod veggies { 20 | pub const CUCUMBER: &'static str = "Cucumber"; 21 | pub const CARROT: &'static str = "Carrot"; 22 | } 23 | } 24 | 25 | fn main() { 26 | println!( 27 | "favorite snacks: {} and {}", 28 | delicious_snacks::fruit, 29 | delicious_snacks::veggie 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/modules/modules3.rs: -------------------------------------------------------------------------------- 1 | // modules3.rs 2 | // You can use the 'use' keyword to bring module paths from modules from anywhere 3 | // and especially from the Rust standard library into your scope. 4 | // Bring SystemTime and UNIX_EPOCH 5 | // from the std::time module. Bonus style points if you can do it with one line! 6 | // Make me compile! Execute `rustlings hint modules3` for hints :) 7 | 8 | // I AM NOT DONE 9 | 10 | // TODO: Complete this use statement 11 | use ??? 12 | 13 | fn main() { 14 | match SystemTime::now().duration_since(UNIX_EPOCH) { 15 | Ok(n) => println!("1970-01-01 00:00:00 UTC was {} seconds ago!", n.as_secs()), 16 | Err(_) => panic!("SystemTime before UNIX EPOCH!"), 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/move_semantics/README.md: -------------------------------------------------------------------------------- 1 | # Move Semantics 2 | 3 | These exercises are adapted from [pnkfelix](https://github.com/pnkfelix)'s [Rust Tutorial](https://pnkfelix.github.io/rust-examples-icfp2014/) -- Thank you Felix!!! 4 | 5 | ## Further information 6 | 7 | For this section, the book links are especially important. 8 | 9 | - [Ownership](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) 10 | - [Reference and borrowing](https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html) 11 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/move_semantics/move_semantics1.rs: -------------------------------------------------------------------------------- 1 | // move_semantics1.rs 2 | // Make me compile! Execute `rustlings hint move_semantics1` for hints :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let vec0 = Vec::new(); 8 | 9 | let vec1 = fill_vec(vec0); 10 | 11 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 12 | 13 | vec1.push(88); 14 | 15 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 16 | } 17 | 18 | fn fill_vec(vec: Vec) -> Vec { 19 | let mut vec = vec; 20 | 21 | vec.push(22); 22 | vec.push(44); 23 | vec.push(66); 24 | 25 | vec 26 | } 27 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/move_semantics/move_semantics2.rs: -------------------------------------------------------------------------------- 1 | // move_semantics2.rs 2 | // Make me compile without changing line 13! 3 | // Execute `rustlings hint move_semantics2` for hints :) 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | let vec0 = Vec::new(); 9 | 10 | let mut vec1 = fill_vec(vec0); 11 | 12 | // Do not change the following line! 13 | println!("{} has length {} content `{:?}`", "vec0", vec0.len(), vec0); 14 | 15 | vec1.push(88); 16 | 17 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 18 | } 19 | 20 | fn fill_vec(vec: Vec) -> Vec { 21 | let mut vec = vec; 22 | 23 | vec.push(22); 24 | vec.push(44); 25 | vec.push(66); 26 | 27 | vec 28 | } 29 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/move_semantics/move_semantics3.rs: -------------------------------------------------------------------------------- 1 | // move_semantics3.rs 2 | // Make me compile without adding new lines-- just changing existing lines! 3 | // (no lines with multiple semicolons necessary!) 4 | // Execute `rustlings hint move_semantics3` for hints :) 5 | 6 | // I AM NOT DONE 7 | 8 | fn main() { 9 | let vec0 = Vec::new(); 10 | 11 | let mut vec1 = fill_vec(vec0); 12 | 13 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 14 | 15 | vec1.push(88); 16 | 17 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 18 | } 19 | 20 | fn fill_vec(vec: Vec) -> Vec { 21 | vec.push(22); 22 | vec.push(44); 23 | vec.push(66); 24 | 25 | vec 26 | } 27 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/move_semantics/move_semantics4.rs: -------------------------------------------------------------------------------- 1 | // move_semantics4.rs 2 | // Refactor this code so that instead of having `vec0` and creating the vector 3 | // in `fn main`, we create it within `fn fill_vec` and transfer the 4 | // freshly created vector from fill_vec to its caller. 5 | // Execute `rustlings hint move_semantics4` for hints! 6 | 7 | // I AM NOT DONE 8 | 9 | fn main() { 10 | let vec0 = Vec::new(); 11 | 12 | let mut vec1 = fill_vec(vec0); 13 | 14 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 15 | 16 | vec1.push(88); 17 | 18 | println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1); 19 | } 20 | 21 | // `fill_vec()` no longer takes `vec: Vec` as argument 22 | fn fill_vec() -> Vec { 23 | let mut vec = vec; 24 | 25 | vec.push(22); 26 | vec.push(44); 27 | vec.push(66); 28 | 29 | vec 30 | } 31 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/move_semantics/move_semantics5.rs: -------------------------------------------------------------------------------- 1 | // move_semantics5.rs 2 | // Make me compile only be reordering the lines in `main()`, but without 3 | // adding, changing or removing any of them. 4 | // Execute `rustlings hint move_semantics5` for hints :) 5 | 6 | // I AM NOT DONE 7 | 8 | fn main() { 9 | let mut x = 100; 10 | let y = &mut x; 11 | let z = &mut x; 12 | *y += 100; 13 | *z += 1000; 14 | assert_eq!(x, 1200); 15 | } 16 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/option/README.md: -------------------------------------------------------------------------------- 1 | # Option 2 | 3 | Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not. 4 | Option types are very common in Rust code, as they have a number of uses: 5 | - Initial values 6 | - Return values for functions that are not defined over their entire input range (partial functions) 7 | - Return value for otherwise reporting simple errors, where None is returned on error 8 | - Optional struct fields 9 | - Struct fields that can be loaned or "taken" 10 | - Optional function arguments 11 | - Nullable pointers 12 | - Swapping things out of difficult situations 13 | 14 | ## Further Information 15 | 16 | - [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions) 17 | - [Option Module Documentation](https://doc.rust-lang.org/std/option/) 18 | - [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html) 19 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/option/option1.rs: -------------------------------------------------------------------------------- 1 | // option1.rs 2 | // Make me compile! Execute `rustlings hint option1` for hints 3 | 4 | // I AM NOT DONE 5 | 6 | // you can modify anything EXCEPT for this function's sig 7 | fn print_number(maybe_number: Option) { 8 | println!("printing: {}", maybe_number.unwrap()); 9 | } 10 | 11 | fn main() { 12 | print_number(13); 13 | print_number(99); 14 | 15 | let mut numbers: [Option; 5]; 16 | for iter in 0..5 { 17 | let number_to_add: u16 = { 18 | ((iter * 1235) + 2) / (4 * 16) 19 | }; 20 | 21 | numbers[iter as usize] = number_to_add; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/option/option2.rs: -------------------------------------------------------------------------------- 1 | // option2.rs 2 | // Make me compile! Execute `rustlings hint option2` for hints 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let optional_word = Some(String::from("rustlings")); 8 | // TODO: Make this an if let statement whose value is "Some" type 9 | word = optional_word { 10 | println!("The word is: {}", word); 11 | } else { 12 | println!("The optional word doesn't contain anything"); 13 | } 14 | 15 | let mut optional_integers_vec: Vec> = Vec::new(); 16 | for x in 1..10 { 17 | optional_integers_vec.push(Some(x)); 18 | } 19 | 20 | // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option 21 | // You can stack `Option`'s into while let and if let 22 | integer = optional_integers_vec.pop() { 23 | println!("current value: {}", integer); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/option/option3.rs: -------------------------------------------------------------------------------- 1 | // option3.rs 2 | // Make me compile! Execute `rustlings hint option3` for hints 3 | 4 | // I AM NOT DONE 5 | 6 | struct Point { 7 | x: i32, 8 | y: i32, 9 | } 10 | 11 | fn main() { 12 | let y: Option = Some(Point { x: 100, y: 200 }); 13 | 14 | match y { 15 | Some(p) => println!("Co-ordinates are {},{} ", p.x, p.y), 16 | _ => println!("no match"), 17 | } 18 | y; // Fix without deleting this line. 19 | } 20 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/README.md: -------------------------------------------------------------------------------- 1 | # Primitive Types 2 | 3 | Rust has a couple of basic types that are directly implemented into the 4 | compiler. In this section, we'll go through the most important ones. 5 | 6 | ## Further information 7 | 8 | - [Data Types](https://doc.rust-lang.org/stable/book/ch03-02-data-types.html) 9 | - [The Slice Type](https://doc.rust-lang.org/stable/book/ch04-03-slices.html) 10 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/primitive_types1.rs: -------------------------------------------------------------------------------- 1 | // primitive_types1.rs 2 | // Fill in the rest of the line that has code missing! 3 | // No hints, there's no tricks, just get used to typing these :) 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | // Booleans (`bool`) 9 | 10 | let is_morning = true; 11 | if is_morning { 12 | println!("Good morning!"); 13 | } 14 | 15 | let // Finish the rest of this line like the example! Or make it be false! 16 | if is_evening { 17 | println!("Good evening!"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/primitive_types2.rs: -------------------------------------------------------------------------------- 1 | // primitive_types2.rs 2 | // Fill in the rest of the line that has code missing! 3 | // No hints, there's no tricks, just get used to typing these :) 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | // Characters (`char`) 9 | 10 | let my_first_initial = 'C'; 11 | if my_first_initial.is_alphabetic() { 12 | println!("Alphabetical!"); 13 | } else if my_first_initial.is_numeric() { 14 | println!("Numerical!"); 15 | } else { 16 | println!("Neither alphabetic nor numeric!"); 17 | } 18 | 19 | let // Finish this line like the example! What's your favorite character? 20 | // Try a letter, try a number, try a special character, try a character 21 | // from a different language than your own, try an emoji! 22 | if your_character.is_alphabetic() { 23 | println!("Alphabetical!"); 24 | } else if your_character.is_numeric() { 25 | println!("Numerical!"); 26 | } else { 27 | println!("Neither alphabetic nor numeric!"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/primitive_types3.rs: -------------------------------------------------------------------------------- 1 | // primitive_types3.rs 2 | // Create an array with at least 100 elements in it where the ??? is. 3 | // Execute `rustlings hint primitive_types3` for hints! 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | let a = ??? 9 | 10 | if a.len() >= 100 { 11 | println!("Wow, that's a big array!"); 12 | } else { 13 | println!("Meh, I eat arrays like that for breakfast."); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/primitive_types4.rs: -------------------------------------------------------------------------------- 1 | // primitive_types4.rs 2 | // Get a slice out of Array a where the ??? is so that the test passes. 3 | // Execute `rustlings hint primitive_types4` for hints!! 4 | 5 | // I AM NOT DONE 6 | 7 | #[test] 8 | fn slice_out_of_array() { 9 | let a = [1, 2, 3, 4, 5]; 10 | 11 | let nice_slice = ??? 12 | 13 | assert_eq!([2, 3, 4], nice_slice) 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/primitive_types5.rs: -------------------------------------------------------------------------------- 1 | // primitive_types5.rs 2 | // Destructure the `cat` tuple so that the println will work. 3 | // Execute `rustlings hint primitive_types5` for hints! 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | let cat = ("Furry McFurson", 3.5); 9 | let /* your pattern here */ = cat; 10 | 11 | println!("{} is {} years old.", name, age); 12 | } 13 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/primitive_types/primitive_types6.rs: -------------------------------------------------------------------------------- 1 | // primitive_types6.rs 2 | // Use a tuple index to access the second element of `numbers`. 3 | // You can put the expression for the second element where ??? is so that the test passes. 4 | // Execute `rustlings hint primitive_types6` for hints! 5 | 6 | // I AM NOT DONE 7 | 8 | #[test] 9 | fn indexing_tuple() { 10 | let numbers = (1, 2, 3); 11 | // Replace below ??? with the tuple indexing syntax. 12 | let second = ???; 13 | 14 | assert_eq!(2, second, 15 | "This is not the 2nd number in the tuple!") 16 | } 17 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/quiz1.rs: -------------------------------------------------------------------------------- 1 | // quiz1.rs 2 | // This is a quiz for the following sections: 3 | // - Variables 4 | // - Functions 5 | 6 | // Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy 7 | // more than 40 at once, each apple only costs 1! Write a function that calculates 8 | // the price of an order of apples given the quantity bought. No hints this time! 9 | 10 | // I AM NOT DONE 11 | 12 | // Put your function here! 13 | // fn calculate_apple_price { 14 | 15 | // Don't modify this function! 16 | #[test] 17 | fn verify_test() { 18 | let price1 = calculate_apple_price(35); 19 | let price2 = calculate_apple_price(40); 20 | let price3 = calculate_apple_price(65); 21 | 22 | assert_eq!(70, price1); 23 | assert_eq!(80, price2); 24 | assert_eq!(65, price3); 25 | } 26 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/quiz2.rs: -------------------------------------------------------------------------------- 1 | // quiz2.rs 2 | // This is a quiz for the following sections: 3 | // - Strings 4 | 5 | // Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your 6 | // task is to call one of these two functions on each value depending on what 7 | // you think each value is. That is, add either `string_slice` or `string` 8 | // before the parentheses on each line. If you're right, it will compile! 9 | 10 | // I AM NOT DONE 11 | 12 | fn string_slice(arg: &str) { 13 | println!("{}", arg); 14 | } 15 | fn string(arg: String) { 16 | println!("{}", arg); 17 | } 18 | 19 | fn main() { 20 | ???("blue"); 21 | ???("red".to_string()); 22 | ???(String::from("hi")); 23 | ???("rust is fun!".to_owned()); 24 | ???("nice weather".into()); 25 | ???(format!("Interpolation {}", "Station")); 26 | ???(&String::from("abc")[0..1]); 27 | ???(" hello there ".trim()); 28 | ???("Happy Monday!".to_string().replace("Mon", "Tues")); 29 | ???("mY sHiFt KeY iS sTiCkY".to_lowercase()); 30 | } 31 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/quiz3.rs: -------------------------------------------------------------------------------- 1 | // quiz3.rs 2 | // This is a quiz for the following sections: 3 | // - Tests 4 | 5 | // This quiz isn't testing our function -- make it do that in such a way that 6 | // the test passes. Then write a second test that tests that we get the result 7 | // we expect to get when we call `times_two` with a negative number. 8 | // No hints, you can do this :) 9 | 10 | // I AM NOT DONE 11 | 12 | pub fn times_two(num: i32) -> i32 { 13 | num * 2 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn returns_twice_of_positive_numbers() { 22 | assert_eq!(times_two(4), ???); 23 | } 24 | 25 | #[test] 26 | fn returns_twice_of_negative_numbers() { 27 | // TODO replace unimplemented!() with an assert for `times_two(-4)` 28 | unimplemented!() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/quiz4.rs: -------------------------------------------------------------------------------- 1 | // quiz4.rs 2 | // This quiz covers the sections: 3 | // - Modules 4 | // - Macros 5 | 6 | // Write a macro that passes the quiz! No hints this time, you can do it! 7 | 8 | // I AM NOT DONE 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::*; 13 | 14 | #[test] 15 | fn test_my_macro_world() { 16 | assert_eq!(my_macro!("world!"), "Hello world!"); 17 | } 18 | 19 | #[test] 20 | fn test_my_macro_goodbye() { 21 | assert_eq!(my_macro!("goodbye!"), "Hello goodbye!"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/README.md: -------------------------------------------------------------------------------- 1 | # Standard library types 2 | 3 | This section will teach you about Box, Shared-State Concurrency and Iterators. 4 | 5 | ## Further information 6 | 7 | - [Using Box to Point to Data on the Heap](https://doc.rust-lang.org/book/ch15-01-box.html) 8 | - [Shared-State Concurrency](https://doc.rust-lang.org/book/ch16-03-shared-state.html) 9 | - [Iterator](https://doc.rust-lang.org/book/ch13-02-iterators.html) 10 | - [Iterator documentation](https://doc.rust-lang.org/stable/std/iter/) 11 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/arc1.rs: -------------------------------------------------------------------------------- 1 | // arc1.rs 2 | // In this exercise, we are given a Vec of u32 called "numbers" with values ranging 3 | // from 0 to 99 -- [ 0, 1, 2, ..., 98, 99 ] 4 | // We would like to use this set of numbers within 8 different threads simultaneously. 5 | // Each thread is going to get the sum of every eighth value, with an offset. 6 | // The first thread (offset 0), will sum 0, 8, 16, ... 7 | // The second thread (offset 1), will sum 1, 9, 17, ... 8 | // The third thread (offset 2), will sum 2, 10, 18, ... 9 | // ... 10 | // The eighth thread (offset 7), will sum 7, 15, 23, ... 11 | 12 | // Because we are using threads, our values need to be thread-safe. Therefore, 13 | // we are using Arc. We need to make a change in each of the two TODOs. 14 | 15 | 16 | // Make this code compile by filling in a value for `shared_numbers` where the 17 | // first TODO comment is, and create an initial binding for `child_numbers` 18 | // where the second TODO comment is. Try not to create any copies of the `numbers` Vec! 19 | // Execute `rustlings hint arc1` for hints :) 20 | 21 | // I AM NOT DONE 22 | 23 | #![forbid(unused_imports)] // Do not change this, (or the next) line. 24 | use std::sync::Arc; 25 | use std::thread; 26 | 27 | fn main() { 28 | let numbers: Vec<_> = (0..100u32).collect(); 29 | let shared_numbers = // TODO 30 | let mut joinhandles = Vec::new(); 31 | 32 | for offset in 0..8 { 33 | let child_numbers = // TODO 34 | joinhandles.push(thread::spawn(move || { 35 | let mut i = offset; 36 | let mut sum = 0; 37 | while i < child_numbers.len() { 38 | sum += child_numbers[i]; 39 | i += 8; 40 | } 41 | println!("Sum of offset {} is {}", offset, sum); 42 | })); 43 | } 44 | for handle in joinhandles.into_iter() { 45 | handle.join().unwrap(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/box1.rs: -------------------------------------------------------------------------------- 1 | // box1.rs 2 | // 3 | // At compile time, Rust needs to know how much space a type takes up. This becomes problematic 4 | // for recursive types, where a value can have as part of itself another value of the same type. 5 | // To get around the issue, we can use a `Box` - a smart pointer used to store data on the heap, 6 | // which also allows us to wrap a recursive type. 7 | // 8 | // The recursive type we're implementing in this exercise is the `cons list` - a data structure 9 | // frequently found in functional programming languages. Each item in a cons list contains two 10 | // elements: the value of the current item and the next item. The last item is a value called `Nil`. 11 | // 12 | // Step 1: use a `Box` in the enum definition to make the code compile 13 | // Step 2: create both empty and non-empty cons lists by replacing `unimplemented!()` 14 | // 15 | // Note: the tests should not be changed 16 | // 17 | // Execute `rustlings hint box1` for hints :) 18 | 19 | // I AM NOT DONE 20 | 21 | #[derive(PartialEq, Debug)] 22 | pub enum List { 23 | Cons(i32, List), 24 | Nil, 25 | } 26 | 27 | fn main() { 28 | println!("This is an empty cons list: {:?}", create_empty_list()); 29 | println!( 30 | "This is a non-empty cons list: {:?}", 31 | create_non_empty_list() 32 | ); 33 | } 34 | 35 | pub fn create_empty_list() -> List { 36 | unimplemented!() 37 | } 38 | 39 | pub fn create_non_empty_list() -> List { 40 | unimplemented!() 41 | } 42 | 43 | #[cfg(test)] 44 | mod tests { 45 | use super::*; 46 | 47 | #[test] 48 | fn test_create_empty_list() { 49 | assert_eq!(List::Nil, create_empty_list()) 50 | } 51 | 52 | #[test] 53 | fn test_create_non_empty_list() { 54 | assert_ne!(create_empty_list(), create_non_empty_list()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/iterators1.rs: -------------------------------------------------------------------------------- 1 | // iterators1.rs 2 | // 3 | // Make me compile by filling in the `???`s 4 | // 5 | // When performing operations on elements within a collection, iterators are essential. 6 | // This module helps you get familiar with the structure of using an iterator and 7 | // how to go through elements within an iterable collection. 8 | // 9 | // Execute `rustlings hint iterators1` for hints :D 10 | 11 | // I AM NOT DONE 12 | 13 | fn main () { 14 | let my_fav_fruits = vec!["banana", "custard apple", "avocado", "peach", "raspberry"]; 15 | 16 | let mut my_iterable_fav_fruits = ???; // TODO: Step 1 17 | 18 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana")); 19 | assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2 20 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado")); 21 | assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1 22 | assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry")); 23 | assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3 24 | } 25 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/iterators2.rs: -------------------------------------------------------------------------------- 1 | // iterators2.rs 2 | // In this exercise, you'll learn some of the unique advantages that iterators 3 | // can offer. Follow the steps to complete the exercise. 4 | // As always, there are hints if you execute `rustlings hint iterators2`! 5 | 6 | // I AM NOT DONE 7 | 8 | // Step 1. 9 | // Complete the `capitalize_first` function. 10 | // "hello" -> "Hello" 11 | pub fn capitalize_first(input: &str) -> String { 12 | let mut c = input.chars(); 13 | match c.next() { 14 | None => String::new(), 15 | Some(first) => ???, 16 | } 17 | } 18 | 19 | // Step 2. 20 | // Apply the `capitalize_first` function to a slice of string slices. 21 | // Return a vector of strings. 22 | // ["hello", "world"] -> ["Hello", "World"] 23 | pub fn capitalize_words_vector(words: &[&str]) -> Vec { 24 | vec![] 25 | } 26 | 27 | // Step 3. 28 | // Apply the `capitalize_first` function again to a slice of string slices. 29 | // Return a single string. 30 | // ["hello", " ", "world"] -> "Hello World" 31 | pub fn capitalize_words_string(words: &[&str]) -> String { 32 | String::new() 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::*; 38 | 39 | #[test] 40 | fn test_success() { 41 | assert_eq!(capitalize_first("hello"), "Hello"); 42 | } 43 | 44 | #[test] 45 | fn test_empty() { 46 | assert_eq!(capitalize_first(""), ""); 47 | } 48 | 49 | #[test] 50 | fn test_iterate_string_vec() { 51 | let words = vec!["hello", "world"]; 52 | assert_eq!(capitalize_words_vector(&words), ["Hello", "World"]); 53 | } 54 | 55 | #[test] 56 | fn test_iterate_into_string() { 57 | let words = vec!["hello", " ", "world"]; 58 | assert_eq!(capitalize_words_string(&words), "Hello World"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/iterators3.rs: -------------------------------------------------------------------------------- 1 | // iterators3.rs 2 | // This is a bigger exercise than most of the others! You can do it! 3 | // Here is your mission, should you choose to accept it: 4 | // 1. Complete the divide function to get the first four tests to pass. 5 | // 2. Get the remaining tests to pass by completing the result_with_list and 6 | // list_of_results functions. 7 | // Execute `rustlings hint iterators3` to get some hints! 8 | 9 | // I AM NOT DONE 10 | 11 | #[derive(Debug, PartialEq, Eq)] 12 | pub enum DivisionError { 13 | NotDivisible(NotDivisibleError), 14 | DivideByZero, 15 | } 16 | 17 | #[derive(Debug, PartialEq, Eq)] 18 | pub struct NotDivisibleError { 19 | dividend: i32, 20 | divisor: i32, 21 | } 22 | 23 | // Calculate `a` divided by `b` if `a` is evenly divisible by `b`. 24 | // Otherwise, return a suitable error. 25 | pub fn divide(a: i32, b: i32) -> Result {} 26 | 27 | // Complete the function and return a value of the correct type so the test passes. 28 | // Desired output: Ok([1, 11, 1426, 3]) 29 | fn result_with_list() -> () { 30 | let numbers = vec![27, 297, 38502, 81]; 31 | let division_results = numbers.into_iter().map(|n| divide(n, 27)); 32 | } 33 | 34 | // Complete the function and return a value of the correct type so the test passes. 35 | // Desired output: [Ok(1), Ok(11), Ok(1426), Ok(3)] 36 | fn list_of_results() -> () { 37 | let numbers = vec![27, 297, 38502, 81]; 38 | let division_results = numbers.into_iter().map(|n| divide(n, 27)); 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use super::*; 44 | 45 | #[test] 46 | fn test_success() { 47 | assert_eq!(divide(81, 9), Ok(9)); 48 | } 49 | 50 | #[test] 51 | fn test_not_divisible() { 52 | assert_eq!( 53 | divide(81, 6), 54 | Err(DivisionError::NotDivisible(NotDivisibleError { 55 | dividend: 81, 56 | divisor: 6 57 | })) 58 | ); 59 | } 60 | 61 | #[test] 62 | fn test_divide_by_0() { 63 | assert_eq!(divide(81, 0), Err(DivisionError::DivideByZero)); 64 | } 65 | 66 | #[test] 67 | fn test_divide_0_by_something() { 68 | assert_eq!(divide(0, 81), Ok(0)); 69 | } 70 | 71 | #[test] 72 | fn test_result_with_list() { 73 | assert_eq!(format!("{:?}", result_with_list()), "Ok([1, 11, 1426, 3])"); 74 | } 75 | 76 | #[test] 77 | fn test_list_of_results() { 78 | assert_eq!( 79 | format!("{:?}", list_of_results()), 80 | "[Ok(1), Ok(11), Ok(1426), Ok(3)]" 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/iterators4.rs: -------------------------------------------------------------------------------- 1 | // iterators4.rs 2 | 3 | // I AM NOT DONE 4 | 5 | pub fn factorial(num: u64) -> u64 { 6 | // Complete this function to return the factorial of num 7 | // Do not use: 8 | // - return 9 | // Try not to use: 10 | // - imperative style loops (for, while) 11 | // - additional variables 12 | // For an extra challenge, don't use: 13 | // - recursion 14 | // Execute `rustlings hint iterators4` for hints. 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::*; 20 | 21 | #[test] 22 | fn factorial_of_1() { 23 | assert_eq!(1, factorial(1)); 24 | } 25 | #[test] 26 | fn factorial_of_2() { 27 | assert_eq!(2, factorial(2)); 28 | } 29 | 30 | #[test] 31 | fn factorial_of_4() { 32 | assert_eq!(24, factorial(4)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/standard_library_types/iterators5.rs: -------------------------------------------------------------------------------- 1 | // iterators5.rs 2 | // Let's define a simple model to track Rustlings exercise progress. Progress 3 | // will be modelled using a hash map. The name of the exercise is the key and 4 | // the progress is the value. Two counting functions were created to count the 5 | // number of exercises with a given progress. These counting functions use 6 | // imperative style for loops. Recreate this counting functionality using 7 | // iterators. Only the two iterator methods (count_iterator and 8 | // count_collection_iterator) need to be modified. 9 | // Execute `rustlings hint iterators5` for hints. 10 | // 11 | // Make the code compile and the tests pass. 12 | 13 | // I AM NOT DONE 14 | 15 | use std::collections::HashMap; 16 | 17 | #[derive(Clone, Copy, PartialEq, Eq)] 18 | enum Progress { 19 | None, 20 | Some, 21 | Complete, 22 | } 23 | 24 | fn count_for(map: &HashMap, value: Progress) -> usize { 25 | let mut count = 0; 26 | for val in map.values() { 27 | if val == &value { 28 | count += 1; 29 | } 30 | } 31 | count 32 | } 33 | 34 | fn count_iterator(map: &HashMap, value: Progress) -> usize { 35 | // map is a hashmap with String keys and Progress values. 36 | // map = { "variables1": Complete, "from_str": None, ... } 37 | } 38 | 39 | fn count_collection_for(collection: &[HashMap], value: Progress) -> usize { 40 | let mut count = 0; 41 | for map in collection { 42 | for val in map.values() { 43 | if val == &value { 44 | count += 1; 45 | } 46 | } 47 | } 48 | count 49 | } 50 | 51 | fn count_collection_iterator(collection: &[HashMap], value: Progress) -> usize { 52 | // collection is a slice of hashmaps. 53 | // collection = [{ "variables1": Complete, "from_str": None, ... }, 54 | // { "variables2": Complete, ... }, ... ] 55 | } 56 | 57 | #[cfg(test)] 58 | mod tests { 59 | use super::*; 60 | 61 | #[test] 62 | fn count_complete() { 63 | let map = get_map(); 64 | assert_eq!(3, count_iterator(&map, Progress::Complete)); 65 | } 66 | 67 | #[test] 68 | fn count_equals_for() { 69 | let map = get_map(); 70 | assert_eq!( 71 | count_for(&map, Progress::Complete), 72 | count_iterator(&map, Progress::Complete) 73 | ); 74 | } 75 | 76 | #[test] 77 | fn count_collection_complete() { 78 | let collection = get_vec_map(); 79 | assert_eq!( 80 | 6, 81 | count_collection_iterator(&collection, Progress::Complete) 82 | ); 83 | } 84 | 85 | #[test] 86 | fn count_collection_equals_for() { 87 | let collection = get_vec_map(); 88 | assert_eq!( 89 | count_collection_for(&collection, Progress::Complete), 90 | count_collection_iterator(&collection, Progress::Complete) 91 | ); 92 | } 93 | 94 | fn get_map() -> HashMap { 95 | use Progress::*; 96 | 97 | let mut map = HashMap::new(); 98 | map.insert(String::from("variables1"), Complete); 99 | map.insert(String::from("functions1"), Complete); 100 | map.insert(String::from("hashmap1"), Complete); 101 | map.insert(String::from("arc1"), Some); 102 | map.insert(String::from("as_ref_mut"), None); 103 | map.insert(String::from("from_str"), None); 104 | 105 | map 106 | } 107 | 108 | fn get_vec_map() -> Vec> { 109 | use Progress::*; 110 | 111 | let map = get_map(); 112 | 113 | let mut other = HashMap::new(); 114 | other.insert(String::from("variables2"), Complete); 115 | other.insert(String::from("functions2"), Complete); 116 | other.insert(String::from("if1"), Complete); 117 | other.insert(String::from("from_into"), None); 118 | other.insert(String::from("try_from_into"), None); 119 | 120 | vec![map, other] 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/strings/README.md: -------------------------------------------------------------------------------- 1 | # Strings 2 | 3 | Rust has two string types, a string slice (`&str`) and an owned string (`String`). 4 | We're not going to dictate when you should use which one, but we'll show you how 5 | to identify and create them, as well as use them. 6 | 7 | ## Further information 8 | 9 | - [Strings](https://doc.rust-lang.org/book/ch08-02-strings.html) 10 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/strings/strings1.rs: -------------------------------------------------------------------------------- 1 | // strings1.rs 2 | // Make me compile without changing the function signature! 3 | // Execute `rustlings hint strings1` for hints ;) 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | let answer = current_favorite_color(); 9 | println!("My current favorite color is {}", answer); 10 | } 11 | 12 | fn current_favorite_color() -> String { 13 | "blue" 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/strings/strings2.rs: -------------------------------------------------------------------------------- 1 | // strings2.rs 2 | // Make me compile without changing the function signature! 3 | // Execute `rustlings hint strings2` for hints :) 4 | 5 | // I AM NOT DONE 6 | 7 | fn main() { 8 | let word = String::from("green"); // Try not changing this line :) 9 | if is_a_color_word(word) { 10 | println!("That is a color word I know!"); 11 | } else { 12 | println!("That is not a color word I know."); 13 | } 14 | } 15 | 16 | fn is_a_color_word(attempt: &str) -> bool { 17 | attempt == "green" || attempt == "blue" || attempt == "red" 18 | } 19 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/structs/README.md: -------------------------------------------------------------------------------- 1 | # Structs 2 | 3 | Rust has three struct types: a classic C struct, a tuple struct, and a unit struct. 4 | 5 | ## Further information 6 | 7 | - [Structures](https://doc.rust-lang.org/book/ch05-01-defining-structs.html) 8 | - [Method Syntax](https://doc.rust-lang.org/book/ch05-03-method-syntax.html) 9 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/structs/structs1.rs: -------------------------------------------------------------------------------- 1 | // structs1.rs 2 | // Address all the TODOs to make the tests pass! 3 | 4 | // I AM NOT DONE 5 | 6 | struct ColorClassicStruct { 7 | // TODO: Something goes here 8 | } 9 | 10 | struct ColorTupleStruct(/* TODO: Something goes here */); 11 | 12 | #[derive(Debug)] 13 | struct UnitStruct; 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | use super::*; 18 | 19 | #[test] 20 | fn classic_c_structs() { 21 | // TODO: Instantiate a classic c struct! 22 | // let green = 23 | 24 | assert_eq!(green.name, "green"); 25 | assert_eq!(green.hex, "#00FF00"); 26 | } 27 | 28 | #[test] 29 | fn tuple_structs() { 30 | // TODO: Instantiate a tuple struct! 31 | // let green = 32 | 33 | assert_eq!(green.0, "green"); 34 | assert_eq!(green.1, "#00FF00"); 35 | } 36 | 37 | #[test] 38 | fn unit_structs() { 39 | // TODO: Instantiate a unit struct! 40 | // let unit_struct = 41 | let message = format!("{:?}s are fun!", unit_struct); 42 | 43 | assert_eq!(message, "UnitStructs are fun!"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/structs/structs2.rs: -------------------------------------------------------------------------------- 1 | // structs2.rs 2 | // Address all the TODOs to make the tests pass! 3 | 4 | // I AM NOT DONE 5 | 6 | #[derive(Debug)] 7 | struct Order { 8 | name: String, 9 | year: u32, 10 | made_by_phone: bool, 11 | made_by_mobile: bool, 12 | made_by_email: bool, 13 | item_number: u32, 14 | count: u32, 15 | } 16 | 17 | fn create_order_template() -> Order { 18 | Order { 19 | name: String::from("Bob"), 20 | year: 2019, 21 | made_by_phone: false, 22 | made_by_mobile: false, 23 | made_by_email: true, 24 | item_number: 123, 25 | count: 0, 26 | } 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn your_order() { 35 | let order_template = create_order_template(); 36 | // TODO: Create your own order using the update syntax and template above! 37 | // let your_order = 38 | assert_eq!(your_order.name, "Hacker in Rust"); 39 | assert_eq!(your_order.year, order_template.year); 40 | assert_eq!(your_order.made_by_phone, order_template.made_by_phone); 41 | assert_eq!(your_order.made_by_mobile, order_template.made_by_mobile); 42 | assert_eq!(your_order.made_by_email, order_template.made_by_email); 43 | assert_eq!(your_order.item_number, order_template.item_number); 44 | assert_eq!(your_order.count, 1); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/structs/structs3.rs: -------------------------------------------------------------------------------- 1 | // structs3.rs 2 | // Structs contain data, but can also have logic. In this exercise we have 3 | // defined the Package struct and we want to test some logic attached to it. 4 | // Make the code compile and the tests pass! 5 | // If you have issues execute `rustlings hint structs3` 6 | 7 | // I AM NOT DONE 8 | 9 | #[derive(Debug)] 10 | struct Package { 11 | sender_country: String, 12 | recipient_country: String, 13 | weight_in_grams: i32, 14 | } 15 | 16 | impl Package { 17 | fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package { 18 | if weight_in_grams <= 0 { 19 | // Something goes here... 20 | } else { 21 | return Package { 22 | sender_country, 23 | recipient_country, 24 | weight_in_grams, 25 | }; 26 | } 27 | } 28 | 29 | fn is_international(&self) -> ??? { 30 | // Something goes here... 31 | } 32 | 33 | fn get_fees(&self, cents_per_gram: i32) -> ??? { 34 | // Something goes here... 35 | } 36 | } 37 | 38 | #[cfg(test)] 39 | mod tests { 40 | use super::*; 41 | 42 | #[test] 43 | #[should_panic] 44 | fn fail_creating_weightless_package() { 45 | let sender_country = String::from("Spain"); 46 | let recipient_country = String::from("Austria"); 47 | 48 | Package::new(sender_country, recipient_country, -2210); 49 | } 50 | 51 | #[test] 52 | fn create_international_package() { 53 | let sender_country = String::from("Spain"); 54 | let recipient_country = String::from("Russia"); 55 | 56 | let package = Package::new(sender_country, recipient_country, 1200); 57 | 58 | assert!(package.is_international()); 59 | } 60 | 61 | #[test] 62 | fn create_local_package() { 63 | let sender_country = String::from("Canada"); 64 | let recipient_country = sender_country.clone(); 65 | 66 | let package = Package::new(sender_country, recipient_country, 1200); 67 | 68 | assert!(!package.is_international()); 69 | } 70 | 71 | #[test] 72 | fn calculate_transport_fees() { 73 | let sender_country = String::from("Spain"); 74 | let recipient_country = String::from("Spain"); 75 | 76 | let cents_per_gram = ???; 77 | 78 | let package = Package::new(sender_country, recipient_country, 1500); 79 | 80 | assert_eq!(package.get_fees(cents_per_gram), 4500); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/tests/README.md: -------------------------------------------------------------------------------- 1 | # Tests 2 | 3 | Going out of order from the book to cover tests -- many of the following exercises will ask you to make tests pass! 4 | 5 | ## Further information 6 | 7 | - [Writing Tests](https://doc.rust-lang.org/book/ch11-01-writing-tests.html) 8 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/tests/tests1.rs: -------------------------------------------------------------------------------- 1 | // tests1.rs 2 | // Tests are important to ensure that your code does what you think it should do. 3 | // Tests can be run on this file with the following command: 4 | // rustlings run tests1 5 | 6 | // This test has a problem with it -- make the test compile! Make the test 7 | // pass! Make the test fail! Execute `rustlings hint tests1` for hints :) 8 | 9 | // I AM NOT DONE 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | #[test] 14 | fn you_can_assert() { 15 | assert!(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/tests/tests2.rs: -------------------------------------------------------------------------------- 1 | // tests2.rs 2 | // This test has a problem with it -- make the test compile! Make the test 3 | // pass! Make the test fail! Execute `rustlings hint tests2` for hints :) 4 | 5 | // I AM NOT DONE 6 | 7 | #[cfg(test)] 8 | mod tests { 9 | #[test] 10 | fn you_can_assert_eq() { 11 | assert_eq!(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/tests/tests3.rs: -------------------------------------------------------------------------------- 1 | // tests3.rs 2 | // This test isn't testing our function -- make it do that in such a way that 3 | // the test passes. Then write a second test that tests whether we get the result 4 | // we expect to get when we call `is_even(5)`. 5 | // Execute `rustlings hint tests3` for hints :) 6 | 7 | // I AM NOT DONE 8 | 9 | pub fn is_even(num: i32) -> bool { 10 | num % 2 == 0 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn is_true_when_even() { 19 | assert!(); 20 | } 21 | 22 | #[test] 23 | fn is_false_when_odd() { 24 | assert!(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/threads/README.md: -------------------------------------------------------------------------------- 1 | # Threads 2 | 3 | In most current operating systems, an executed program’s code is run in a process, and the operating system manages multiple processes at once. 4 | Within your program, you can also have independent parts that run simultaneously. The features that run these independent parts are called threads. 5 | 6 | ## Further information 7 | 8 | - [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) 9 | - [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) 10 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/threads/threads1.rs: -------------------------------------------------------------------------------- 1 | // threads1.rs 2 | // Make this compile! Execute `rustlings hint threads1` for hints :) 3 | // The idea is the thread spawned on line 22 is completing jobs while the main thread is 4 | // monitoring progress until 10 jobs are completed. Because of the difference between the 5 | // spawned threads' sleep time, and the waiting threads sleep time, when you see 6 lines 6 | // of "waiting..." and the program ends without timing out when running, 7 | // you've got it :) 8 | 9 | // I AM NOT DONE 10 | 11 | use std::sync::Arc; 12 | use std::thread; 13 | use std::time::Duration; 14 | 15 | struct JobStatus { 16 | jobs_completed: u32, 17 | } 18 | 19 | fn main() { 20 | let status = Arc::new(JobStatus { jobs_completed: 0 }); 21 | let status_shared = status.clone(); 22 | thread::spawn(move || { 23 | for _ in 0..10 { 24 | thread::sleep(Duration::from_millis(250)); 25 | status_shared.jobs_completed += 1; 26 | } 27 | }); 28 | while status.jobs_completed < 10 { 29 | println!("waiting... "); 30 | thread::sleep(Duration::from_millis(500)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/traits/README.md: -------------------------------------------------------------------------------- 1 | # Traits 2 | 3 | A trait is a collection of methods. 4 | 5 | Data types can implement traits. To do so, the methods making up the trait are defined for the data type. For example, the `String` data type implements the `From<&str>` trait. This allows a user to write `String::from("hello")`. 6 | 7 | In this way, traits are somewhat similar to Java interfaces and C++ abstract classes. 8 | 9 | Some additional common Rust traits include: 10 | - `Clone` (the `clone` method) 11 | - `Display` (which allows formatted display via `{}`) 12 | - `Debug` (which allows formatted display via `{:?}`) 13 | 14 | Because traits indicate shared behavior between data types, they are useful when writing generics. 15 | 16 | 17 | ## Further information 18 | 19 | - [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html) 20 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/traits/traits1.rs: -------------------------------------------------------------------------------- 1 | // traits1.rs 2 | // Time to implement some traits! 3 | // 4 | // Your task is to implement the trait 5 | // `AppendBar' for the type `String'. 6 | // 7 | // The trait AppendBar has only one function, 8 | // which appends "Bar" to any object 9 | // implementing this trait. 10 | 11 | // I AM NOT DONE 12 | 13 | trait AppendBar { 14 | fn append_bar(self) -> Self; 15 | } 16 | 17 | impl AppendBar for String { 18 | //Add your code here 19 | } 20 | 21 | fn main() { 22 | let s = String::from("Foo"); 23 | let s = s.append_bar(); 24 | println!("s: {}", s); 25 | } 26 | 27 | #[cfg(test)] 28 | mod tests { 29 | use super::*; 30 | 31 | #[test] 32 | fn is_FooBar() { 33 | assert_eq!(String::from("Foo").append_bar(), String::from("FooBar")); 34 | } 35 | 36 | #[test] 37 | fn is_BarBar() { 38 | assert_eq!( 39 | String::from("").append_bar().append_bar(), 40 | String::from("BarBar") 41 | ); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/traits/traits2.rs: -------------------------------------------------------------------------------- 1 | // traits2.rs 2 | // 3 | // Your task is to implement the trait 4 | // `AppendBar' for a vector of strings. 5 | // 6 | // To implement this trait, consider for 7 | // a moment what it means to 'append "Bar"' 8 | // to a vector of strings. 9 | // 10 | // No boiler plate code this time, 11 | // you can do this! 12 | 13 | // I AM NOT DONE 14 | 15 | trait AppendBar { 16 | fn append_bar(self) -> Self; 17 | } 18 | 19 | //TODO: Add your code here 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use super::*; 24 | 25 | #[test] 26 | fn is_vec_pop_eq_bar() { 27 | let mut foo = vec![String::from("Foo")].append_bar(); 28 | assert_eq!(foo.pop().unwrap(), String::from("Bar")); 29 | assert_eq!(foo.pop().unwrap(), String::from("Foo")); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/README.md: -------------------------------------------------------------------------------- 1 | # Variables 2 | 3 | In Rust, variables are immutable by default. 4 | When a variable is immutable, once a value is bound to a name, you can’t change that value. 5 | You can make them mutable by adding mut in front of the variable name. 6 | 7 | ## Further information 8 | 9 | - [Variables and Mutability](https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html) 10 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/variables1.rs: -------------------------------------------------------------------------------- 1 | // variables1.rs 2 | // Make me compile! Execute the command `rustlings hint variables1` if you want a hint :) 3 | 4 | // About this `I AM NOT DONE` thing: 5 | // We sometimes encourage you to keep trying things on a given exercise, 6 | // even after you already figured it out. If you got everything working and 7 | // feel ready for the next exercise, remove the `I AM NOT DONE` comment below. 8 | 9 | // I AM NOT DONE 10 | 11 | fn main() { 12 | x = 5; 13 | println!("x has the value {}", x); 14 | } 15 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/variables2.rs: -------------------------------------------------------------------------------- 1 | // variables2.rs 2 | // Make me compile! Execute the command `rustlings hint variables2` if you want a hint :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let x; 8 | if x == 10 { 9 | println!("Ten!"); 10 | } else { 11 | println!("Not ten!"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/variables3.rs: -------------------------------------------------------------------------------- 1 | // variables3.rs 2 | // Make me compile! Execute the command `rustlings hint variables3` if you want a hint :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let x = 3; 8 | println!("Number {}", x); 9 | x = 5; // don't change this line 10 | println!("Number {}", x); 11 | } 12 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/variables4.rs: -------------------------------------------------------------------------------- 1 | // variables4.rs 2 | // Make me compile! Execute the command `rustlings hint variables4` if you want a hint :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let x: i32; 8 | println!("Number {}", x); 9 | } 10 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/variables5.rs: -------------------------------------------------------------------------------- 1 | // variables5.rs 2 | // Make me compile! Execute the command `rustlings hint variables5` if you want a hint :) 3 | 4 | // I AM NOT DONE 5 | 6 | fn main() { 7 | let number = "T-H-R-E-E"; // don't change this line 8 | println!("Spell a Number : {}", number); 9 | number = 3; 10 | println!("Number plus two is : {}", number + 2); 11 | } 12 | -------------------------------------------------------------------------------- /tutorial/rustlings/exercises/variables/variables6.rs: -------------------------------------------------------------------------------- 1 | // variables6.rs 2 | // Make me compile! Execute the command `rustlings hint variables6` if you want a hint :) 3 | 4 | // I AM NOT DONE 5 | 6 | const NUMBER = 3; 7 | fn main() { 8 | println!("Number {}", NUMBER); 9 | } 10 | --------------------------------------------------------------------------------