https://github.com/veaba/learn-rust
learn rust, 40+ demos
https://github.com/veaba/learn-rust
cargo learning-rust rust
Last synced: 6 months ago
JSON representation
learn rust, 40+ demos
- Host: GitHub
- URL: https://github.com/veaba/learn-rust
- Owner: veaba
- Created: 2019-03-08T07:13:44.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2022-10-27T14:03:08.000Z (over 3 years ago)
- Last Synced: 2025-01-30T17:39:40.362Z (about 1 year ago)
- Topics: cargo, learning-rust, rust
- Language: Rust
- Homepage:
- Size: 737 KB
- Stars: 1
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# learn-rust
## Book
- https://rust-lang.github.io/rustc-guide/about-this-guide.html rust官方指南
- http://wiki.jikexueyuan.com/project/rust-primer/quickstart/primitive-type.html 极客学院的rust教程
- https://doc.rust-lang.org/std/primitive.f64.html rust 函数库
- https://doc.rust-lang.org/rust-by-example/index.html rust example
- https://rust-lang.github.io/rfcs/ rust rfcs
- https://kaisery.gitbooks.io/trpl-zh-cn/content/ 《Rust 程序设计语言》 中文版
- https://rustwasm.github.io/book/ 《Rust 程序设计语言》 英文版
- https://doc.rust-lang.org/stable/rust-by-example/ 通过例子来学习rust
- https://crates.io/ rust 依赖包
- TODO https://kaisery.github.io/trpl-zh-cn/ch02-00-guessing-game-tutorial.html 猜猜看游戏
- https://rustwiki.org/zh-CN/rust-by-example/std/result.html 中文,例子学习
## 错误
- ^^^ `std::result::Result<_, _>` cannot be formatted with the default formatter
- //#[derive(Debug)]的//去掉时能自动为Student实现std::fmt::Debug特性。
- only valid in field-less enums
- `Employee` cannot be formatted with the default formatter
- `not found in this scope`
```text
pub fn arg_result(arg: String) -> tuple {
| ^^^^^ not found in this scope
error: aborting due to previous error
```
```rust
// use
let ab = utils::arg_result(arg);
println!("arg result==?,{}", ab);
println!("{:?}", arg);
// var utils.rs
pub fn arg_result(arg: String) -> tuple {
// return ("a", "2");
("a","b")
}
```
- `Use of moved value`
- [分析文章](https://www.cnblogs.com/dhcn/p/12152116.html)
编译器说,我们新加入的行里用了“移动了的值”。
啥叫“移动了的值”呢?
说白了就是用过了的值,foo已经给第一个fn_a()用过了,到了第二个fn_a()的时候就是moved value了。然后就不让用了。
至于为什么要制定这样的规则,[解释]()
现在我们开始动手来解决这个问题。
- `returns a value referencing data owned by the current function`
查看例子[lifecycle/lifecycle.rs](lifecycle/lifecycle.rs)
- `cannot return value referencing local variable "temp_arg"`
查看例子[lifecycle/lifecycle.rs](lifecycle/lifecycle.rs)
`explicit lifetime required in the type of `
## 入门知识点
- rust 是静态类型,必须知道类型,且不能随更改类型
- 变量隐藏和复写
```rust
fn main(){
let x =5;
let x=x+1;
let x =x*2;
}
```
- 倒数第二及以前的段落必须结尾加分号
- 函数内部 最后一行如果不用return 的方式返回,就不能给该行使用分号
- 表达式返回值
```rust
fn main(){
let x =five();
println!("{}",x);
}
// 如果函数最后一行不带`return`且不带分号,则认为是一个`return`,可省去关键字`return`
fn five()->i32{
5
}
```
## 疑问
### 1. 如何if == string?
### 2. while循环和for循环的区别:
> 如果数组的索引长度在运行时增加,那么while循环显示错误,但在for循环的情况下不会发生这种情况。 因此,可以说for循环增加了代码的安全性并消除了错误的可能性。
### 3. 为什么要加!
### 4. 使用前,需要将变量声明,不存在js类似的变量提升
### 5. i32表示多少
### 6. 不能打印长元组?? 报错,WHY?
```rust
fn main(){
let too_long_tuple=(1,65,56,6,565,65,95,5,655,656,64,65,5,61,6,5656);
println!("too long tuple:{:?}",too_long_tuple);
}
```
### 7. rust 如何执行一段函数返回的代码,即函数返回值
```rust
/*
* @pair 入参一个,内含两个元素,数据类型为(i32,bool)元组
* @return 返回值为 数据类型为,也是个元组 (bool,i32)
*/
fn reverse(pair:(i32,bool))->(bool,i32){
let (integer,boolean)=pair;
(boolean,integer)
}
fn main(){
let pair = (11,true);
println!("{:?}",reverse(pair));
}
```
### 8. rust 如何计算一个函数加值的运算,涉及到 :入参、返回值,类型
```rust
fn main(){
println!("{}",fool(999));
}
fn fool(num:i32)->(i32){
return num+999; // 或者num+999,不需要return
}
```
### 9. 为什么要加一个&?
答案:表示引用
```rust
use std::mem;
fn analyze_slice(slice:&[i32]){
println!("第一个元素:{}",slice[0]);
println!("数组的长度:{}",slice.len());
}
fn main(){
let xs:[i32;5]=[9898,9856,685659,66,9];
analyze_slice(&xs)//为什么要加一个&呢?
}
```
### 10. match在函数中的作用
- match 由分支(arms)构成,一个分支包含一个模式(pattern)
- match的cmp方法会返回`Ordering:Greater`,`Ordering:Less`,`Ordering:Equal`
```rust
fn inspect(event:WebEvent){
// match干嘛的?
match event {
WebEvent::PageLoad=>println!("page load"),
WebEvent::PageUnload=>println!("page unload"),
WebEvent::Keypress(c)=>println!("pressed '{}'.",c),
WebEvent::Paste(s)=>println!("pasted\"{}\".",s),
WebEvent::Click {x,y}=>println!("click at x={},y={}",x,y)
}
}
```
### 11. 怎么打印枚举
```rust
enum Point{
x = 111
}
println!("{}");
```
### 12. return 部分返回的尖括号?
### 13. Ok(())是什么意义?
- Result 风格,大写Ok,因为它是一个枚举enum
- future中,使用小写ok方法【首选】
### 14. 函数括号加问号?
### 15. 怎么查看type 类型?
### 16. String 转为真正的数字类型
```text
let num:u32=guess.trim().parse().expect('xxx')
```
### 17. 如何取到键盘输入的值
> io::stdin().read_line(&mut xx).expect("错误~~") ,存到一个变量
### 18. TODO 如何迭代/循环元组?
```rust
fn main(){
let long_tuple =(
1u8,2u16,3u32,4u64,
-1i8,-2i16,-3i32,-4i64,
0.1f32,0.2f64,'a',true);
}
```
### 19.TODO,比如test()`?` 这个后面的问号是干嘛的?
### 20. 问号是干嘛的?fs::write("foo.txt","哈哈哈")?;
### 21. 数字转字符串
### 22. 函数后面有个函数是干嘛?
- 由于Rust中没有Exception异常处理的语法,
- Rust只有panic报错, 并且panic不允许被保护, 因为没有提供 try 这种语法.
- Rust的异常处理是通过 Result 的 Ok 和 Err 成员来传递和包裹错误信息.
- 然而错误信息的处理一般都是要通过match来对类型进行比较, 所以很多时候
- 代码比较冗余, 通过?符号来简化Ok和Err的判断.
```rust
use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new().route("/", web::get().to(|| HttpResponse::Ok()))
})
.bind("127.0.0.1:8088")? //What is that ?
.run()
.await
}
```
### 23. 为什么这里会变更掉变量值的类型
` use of moved value`

可以:utils::arg_result(arg.clone())解决问题
### 24. rust 的`impl`
- `impl` 作为关键字定义参数类型
- `impl` 关键字定义指定struct的实现代码,然后在这代码块中定义与struct相关的方法
### 25. rust 中的方法和函数
方法与函数非常相似
- 方法:必须有与之关联的`Struct`,且第一个参数是`self`
```rust
struct Style {
width: u32,
height: u32,
}
impl Style {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Style {
width: 30,
height: 90,
};
println!("{:?}", rect.area())
}
```
### 26 文件调用别的文件的函数方法
```rust
// a.rs
use crate::shared::QRErrorCorrectLevel::H;
// b.rs
pub struct Code {
width: i32,
height: i32,
type_number: i32,
color_dark: String,
color_light: String,
correct_level: H,
}
// main.rs
mod shared;
```
### 27. rust 如何实现类似 js 中的对象
### 28. rust &b"" ??
```rust
use bytes::{Bytes}
fn main(){
let b = Bytes::new();
println("{:?}",&b[..])
}
```
看起来 bytes,声明是 b"", 需要 `&x[..]` 展开,然后是是一个数组
### 29. 引用 Reference
两种引用类型:
- 共享指针:`&`
- 可变指针:`&mut`
规则:
- 引用的生命周期不能超过被引用内容
- 可变引用不能存在别名
### 30. 借用 Borrow
### 31. Rust 生命周期
Rust 会通过分析引用对象的`声明周期`来防止引用一个不可用的对象。
生命周期的主要目标是为了防止`悬空指针`
```rust
{
let r;
{
let x =5;
r = &x; // 被销毁了
}
println!("r :{}",r)
}
```
外部作用域声明了变量`r`,内部作用域声明了变量`x`,在内部产生设置了`r` 为 `x`的引用,当内部区域终止时,尝试打印`r`,上述代码无法通过编译。
查看例子[lifecycle/lifecycle.rs](lifecycle/lifecycle.rs)
### 32. Vec
### 33. rust 函数如何返回一个不定长的数组?
```rust
// error
pub fn arg_array(arg:String) -> &mut [T] {
["a"]
}
// 其中一种方法
pub fn arg_array(arg: String) -> Vec<&'static str> {
println!("入参=>{}", arg);
let array = ["das", "das","dsad"];
println!("len =>{}",array.len());
for i in 0..array.len(){
vec.push(array[i])
}
return vec;
}
```
### 34. rust 结构体里有结构如何打印?
```rust
struct MainModule {
user: String,
// TODO auto 1 2 3 4 5 6
worker_processes: u32,
event: EventModule,
// error_log: String,
// pid: String,
// worker_rlimit_nofile: u32,
// http: HttpModule,
}
struct EventModule {
worker_connections: u32,
}
fn main(){
let config = MainModule {
user: String::from("www www"),
worker_processes: 2
};
println!("==>{:#?}", config.event) // why can;t print this?
}
```
### 35. 类似这种结构,怎么打印Object 返回?
```rust
fn main() {
let object = json_to_struct();
println!("{:#?}", object) // TestStruct` cannot be formatted using `{:?}`
}
fn json_to_struct() -> Result<()> {
let json = r#"
{
"name":"asjdsak",
"age":30,
"type":true
}
"#;
let v: Value = serde_json::from_str(json)?;
println!("==>{:?}", v);
Ok(())
// TODO 如何返回v
}
```
改动如下:
```rust
use serde_json::{Result,Value};
fn main() {
let object = json_to_struct();
println!("{:#?}", object) // TestStruct` cannot be formatted using `{:?}`
}
fn json_to_struct() -> Result {
let json = r#"
{
"name":"asjdsak",
"age":30,
"type":true
}
"#;
let v: Value = serde_json::from_str(json)?;
println!("==>{:?}", v);
Ok(v)
}
```
二次改动
```rust
use serde_json::{Result,Value};
fn main() {
let object = json_to_struct().unwrap();
println!("{:#?}", object); // TestStruct` cannot be formatted using `{:?}`
// println!("{:#?}", object) // TestStruct` cannot be formatted using `{:?}`
// println!("name==>{:#?}", object.name);
println!("=dsadd=>{}", object["name"]);
}
fn json_to_struct() ->Result {
let json = r#"
{
"name":"asjdsak",
"age":30,
"type":true
}
"#;
let v: Value = serde_json::from_str(json)?;
println!("name===>{}",v["name"]);
println!("==>{:?}", v);
Ok(v)
}
```
### 35. json字符串转struct
```rust
extern crate rustc_serialize;
use rustc_serialize::json;
#[derive(RustcDecodable, RustcEncodable)]
#[derive(Debug)]
struct Profile {
name: String,
age: u8,
phones: Vec,
}
fn main() {
let json_str = r#"
{
"name":"veaba",
"age":26,
"phones":[
"110",
"120",
"119"
]
}
"#;
let profile: Profile = json::decode(&json_str).unwrap();
println!("json to struct==>{:#?}", profile);
}
```
### 36. struct转json字符串
```rust
extern crate rustc_serialize;
use rustc_serialize::json;
#[derive(RustcDecodable, RustcEncodable)]
#[derive(Debug)]
struct Profile {
name: String,
age: u8,
phones: Vec,
}
fn main() {
let profile = Profile {
name: "Jobs".to_string(),
age: 99,
// phones: vec!["110", "120", "199", "144"],
phones: vec!["110".to_string(), "120".to_string(), "199".to_string(), "144".to_string()],
};
let encode = json::encode(&profile).unwrap();
println!("struct to json==>{}", encode);
}
```
### 37. struct 打印
- 必须要加`#[derive(Debug)]`,否则无法使用 {:#?}打印struct
- [src/struct/struct.rs](src/struct/struct.rs)
### 38. struct 嵌套struct 如何转为json?
```rust
extern crate rustc_serialize;
use rustc_serialize::json;
// Struct Parent
#[derive(RustcDecodable, RustcEncodable)]
#[derive(Debug)]
struct Parent {
name: String,
age: u8,
children: Children,
}
// Struct Children
#[derive(RustcDecodable, RustcEncodable)]
#[derive(Debug)]
struct Children {
name: String,
age: u8,
school: String,
}
fn main() {
let person = Parent {
name: "Li".to_string(),
age: 35,
children: Children {
name: "Li's son".to_string(),
age: 8,
school: "primary".to_string(),
},
};
println!("no children==>{:#?}", person); // 可以打印出来person
let to_json_str = json::encode(&person).unwrap();
println!("json str==>{}", to_json_str);
}
```
### 39. struct 转普通字符串
也只能参考struct 转 json 字符串
### 40. 可省略的struct
### 41. 禁用无效代码检查
> #[allow(dead_code)]
### 42. 匿名函数 TODO
Rust 使用闭包(`closure`) 来创建匿名函数
```rust
let num=5;
let plus_num= |x:i32| x +num;
```
闭包`plus_num`借用了它的作用域中的`let` 绑定`num`,如想让闭包获取所有权,可以使用`move`关键字:
```rust
let mut num=5;
{
let mut add_num=move |x:i32| num+=x; // 闭包通过move 获取num所有权
add_num(5)
}
```
### 43. 如何合并多个结构?
```rust
fn get_merge_config() {
let default_config = get_default_config();
let outside_config= get_outside_config();
let merge_config=ConfigModule{
default_config, // TODO ??
..outside_config
};
println!("default config===>{:#?}", default_config);
return merge_config;
}
```
### 44. 如何简写if 或操作
```rust
// TODO 如何简写一下代码?
fn main() {
let a = String::from("aa");
let b = String::from("bb");
// let c: String = a | b;
let c;
if a.len() > 0 {
c = a
} else {
c = b
}
println!("{}", c);
}
```
## structures 结构
rust 通过自定义类型主要通过以下两个关键形成:
- struct 声明一个结构
- enum 声明一个枚举
常量可以通过`const` `static` 关键字声明
- const x = 99; 不合适。x推荐大写
- const X=8;错误,X虽然大写,但需要声明数据类型
- const X:u32=999 √
- const mut X:u32=99 常量不接受可变量修饰符
结构:
- 元组结构,基本上是命名为元组的。
- 经典的C结构
- 无字段的单元结构对于泛型很有用
- rust 的结构和解构
```rust
struct Pair(i32,f32);
struct Person<'a> {
name: &'a str,
//这是啥子?
age: u8,
}
fn main(){
let pair =Pair(99,99.9);
let Pair{x,y}=pair; //todo ??
println!("{:?}\n{:?}",x,y);
let name = "Jogel";
let age = 27;
let jogel = Person { name, age };
println!("{:?}",jogel);
}
```
- 如何跨文件使用use
```rust
enum Status{
Rich,
Poor
}
enum Work{
Google,
Microsoft,
}
use Status::{Poor,Rich};
use Work::*;
```
## 定时器
```rust
use std::thread;
use std::time::Duration;
fn main() {
let mut x = 1;
while x < 10 {
println!("{},{}",x,"哈哈哈哈");
x += 1;
thread::sleep(Duration::from_millis(1000));
}
println!("{},{}",x,"哦哦哦");
}
```
## 内存和分配
;
- 堆栈存储器
- 循环放置
- 相反顺序移除
- 遵从`后进先出`,进电梯 原则
- 始终 首先删除最后插入的数据
- `堆栈内存`有组织的内存,比`堆内存`更快
- 访问内存的方式
- 编译时数据大小未知,则`堆内存`用于存储内容
- 堆内存
- `堆内存`是有组织的内存
- os 在`堆内存`中找到一个空的空格并返回一个指针,这叫 `在对上分配`
;
- 第一步
- 向量v1与值 1 2 3 '666'绑定,四个部分组成
- 指向存储器中指向存储在内存的数据的指针 长度和向量的容量
- 这部分存储在堆栈中,二数据存储在堆内存中
;
- 第二步
- `v1` 向量分配给向量`v2`
- 指针,长度、容量将复制到堆栈中
- 但不会讲数据复制到堆内存中
-
- `v1`、`v2` 都超出范围时,两者都会尝试释放内存
- 这会导致双重空闲内存,从而使得内存损坏~
;
- 第三步
- rust 避免了第二步的内存问题
- rust没有复制分配的内存,则认为`v1`向量不再有效
- 当 `v1`超出范围时,它不需要释放`v1`的内存
;
```rust
fn main(){
let v1= vec![1,2,3,"666"];
let v2 = v2;
}
```
### 特征复制
- 复制特征是特殊的注释
- 放在存储堆栈上的整数类型上
- 如果类型使用了复制特征,则复制之后还可以使用旧变量
- 复制类型
- 所有整数类型,如 `u32`
- 布尔类型 `bool`:`true`, `false`
- 所有浮动类型,如`f64`
- 字符类型,如 `char`
### 所有权和函数
## 所有权(ownership)【重点】
### 管理计算机内存的方式
- 垃圾回收机制
- javascript
- java
- 手动分配和释放内存
- C语言
- 所有权系统管理内存
- Rust
### 堆栈知识
编译器在编译时会根据一系列的规则进行检查,runtime,ownership 所有权系统的任何功能不会减慢程序
- [阮一峰:汇编语言入门教程](http://www.ruanyifeng.com/blog/2018/01/assembly-language-primer.html)
- Heap(堆):程序运行时产生,用户去申请的,存储值
- 缺乏组织性
- 大小未知
- 手动请求和分配一块区域存储数,返回地址的指针:这个过程叫:在堆上分配内存
- Stack(栈):push、pop 等相关,函数运行时而临时占用的内存区域。后进先出(叠盘子)
- 访问堆上的数据比访问栈上的数据慢,因为必须通过指针来访问
- 调用函数,传递函数的值(可能是堆上数据的指针)和函数局部变量被压入栈中,当函数结束时,这些值被移除栈。
### 关于rust 所有权的描述
rust的所有权操作,属于新的概念。
## 常识
|name|desc||
|---|---|---|
|.rs|rust文件后缀||
|Cargo.lock|||
|Cargo.toml|||
|xxx.iml|||
|src目录|源码||
|target目录|||
|mnt i| i是可以更改变量,可变变量||
|双引号|给字符/对象||
|str|String::from("a string")||
|char|`a`,单引号是一个单字符,超出则编译错误 `let char = 'a'`||
|&str|`abd`,双引号括住是多个字符 `let a="你好"`||
|return None|||
|return true|||
|return false|||
|return Err(err)|||
|impl|||
|符号整数|i开头||
|无符号整数|u开头,不是负号||
|#[derive(Debug)]|||
|#[allow(dead_code)]|||
|{:?}|打印数组、元组||
|match|rust关键字提供匹配模式,类似C的 `switch`|参考https://doc.rust-lang.org/rust-by-example/flow_control/match.html|
|_|下划线|_=>print!("xx"),类似如果下划线在match中,类似switch 的default:|
||||
### 定义/结论
- rust 变量默认不可改变,如需改变,则需要let mut bar="hello world"
- `let mut foo = String::new()` new 是String类型的关联函数,针对类型实现的,常称:静态方法
- `new` 创建类型实例的惯用函数名
- Result 类型是枚举,枚举(enums),它的值被称为枚举的成员(variants):`ok`,`Err`。
- ok 表示成功
- Error 表示失败
- io::Result,的实例拥有expect方法,`return` 的是一个 输入的字节数`usize`
- rust标准库中尚未包含随机数功能,rust团队提供了 `rand` crate
- `std::cmp::Ordering`类型,`Ordering`也是一个枚举,成员是`Less`(小于),`Greater`(大于),`Equal`(等于),比较两个值的三种结果
- //#[derive(Debug)]的//去掉时能自动为Student实现std::fmt::Debug特性。
- use 枚举名称::*,自动列出枚举名称的名称,少写几次枚举名称,直接写成员
```text
enum Work{
Google,
Microsoft,
Alibaba=999
}
use Work::*;
let work = Google;
let worker =Microsoft;
let taobao =Alibaba;//??
```
- rust 使用 snake case 风格,所有字母都小写并使用下划线分割
- rust 函数声明提升,无论声明在调用之前或之后
- rust 函数的参数必须有类型fn test(arg1:i32,arg2:u64)
- rust 是一门基于表达式的语言(expression-based)
- rust 无法使用`x=y=6`
### 常量和变量的区别
- let 变量
- let x =6 不可变的变量
- let mut x=6 自动推断类型,且可变
- const 常量,大写
- const x = 99; 不合适。x推荐大写
- const X=8;错误,X虽然大写,但需要声明数据类型
- const mut X:u32=99 常量不接受可变量修饰符
- const X:u32=999 √
### 隐藏,shadowing
重复声明的方式来达到变量替换的目的,后者会替换前面的变量
```rust
fn main(){
let mut x = 666;
let x =999;
let mut x = 888;//此处的mut 是多余了
}
```
## install
### version
> rustc --version
### update 更新
> rustup update
### uninstall 下载
> rustup self uninstall
## demo
### 处理一次猜测
- [处理一次猜测](https://kaisery.github.io/trpl-zh-cn/ch02-00-guessing-game-tutorial.html)
```rust
use std::io;
fn main(){
println!("hello world");
let mut guess =String::new(); //?干嘛的,空字符串
println!("请输入:{}",guess);
io::stdin().read_line(&mut guess)
.expect("读取行失败");
println!("你猜的,{}",guess);
}
```
### 猜到对数字
```toml
[package]
name = "learn-rust"
version = "0.1.0"
authors = ["veaba"]
edition = "2018"
[dependencies]
rand="0.3.14"
```
```rust
/**
@desc 步骤分析:
1、生成一个1-100的随机数
2、键盘输入一值
3、loop循环
4、比较大小
*/
use std::io;
use rand::Rng;
use std::cmp::{Ordering,Ord};
fn main() {
let code = rand::thread_rng().gen_range(1,101);
println!("code:{}",code);
loop {
println!("======== 请输入你的字符 ========");
let mut key=String::new();//生成一个类型为String的实例
io::stdin().read_line(&mut key)
.expect("输入错误~");
println!("你输入的:{}",key);
// rust 允许用一个新值来隐藏(shadow)guess之前的值:常用于转换值类型之类的场景,
// 这种用法,允许复用guess便利店个名称,而不是创建两个不同的变量
// 详见:https://kaisery.github.io/trpl-zh-cn/ch03-00-common-programming-concepts.html
let key:u32=match key.trim().parse(){
Ok(num)=>num,
Err(_)=>{
println!("字符类型不对");
continue
}
};
// key 和code 没办法对比,请改为CMP->cmp
match key.CMP(&code) {
Ordering::Less=>println!("太小了"),
Ordering::Greater=>println!("太大了"),
Ordering::Equal=>{
println!("猜中了,biubiu");
break;
}
}
}
}
```
## rustup
## cargo
## 第一个程序
```rust
fn main(){
print!("Hello,world!");
}
```
执行命令
> rustc hello.rs
会生成` hello.exe`、`hello.pdb`,windows 下运行hello.exe才会运行
## 函数
|函数|解释|demo|
|---|---|---|
|format!()|格式化文本写入字符串||
|print!|类似format!,但打印到控制台||
|println!()类似print!但会添加新的一行|||
|eprint!|类型format!,打印为标准错误||
|eprintln!()类似eprint,但会添加新的一行|||
||||
||||
||||
```rust
// ->指返回
fn add_one(x:i32)->i32{
x+1
}
// todo 问号是干嘛的?fs::write("foo.txt","哈哈哈")?;
// let _ = fs::write("foo.txt", "哈哈哈");
```
### 函数发散,不会返回
## 系统/全局函数或方法
### print!()
- print!(双引号),且只能是字符串
```rust
fn main(){
let a=9;
if a==9 {
print!("aaa");
}
}
```
### println!()
```rust
println!("{}","xxx");
println!("{:?}",xxx);
```
### .to_owned()
### .iter()
### match 类似 `switch`
```rust
fn main(){
let number=1;
println!("the number:{}",number);
// prime
match number {
1=>println!("One"),
2=>println!("Two"),
3|4|5|6|7|11=>println!("匹配的数字"),
12...19=>println!("A ten哇"),
// 不是特殊的
_=>println!("default"),
}
let boolean =true;
let binary =match boolean
{
false=>0,
true=>1
};
println!("{}-{}",boolean,binary);
}
```
## if判断语句
```rust
fn main(){
let a=9;
if a==8 {
println!("aaa");
}
else if a>8 {
println!("bbb");
}
else{
println!("ccc");
}
}
```
## if in a let语句
## 错误处理error
- https://doc.rust-lang.org/error-index.html#E0308 rust编译错误索引
> expected integer, found char
> too many characters in char literal 表示只能是单个字符!!a或者b,不能ab
> String::from("S/\q\t\nI}POYY?M>NM>M(&'static str){
let str = "哇哈哈哈";
return str
}
```
## 数组
- 数组每个元素的类型必须相同
- 不可减少长度或者增加长度
### 访问方式 和js 一样 arr[1]
## 数组的函数/方法
## vector 可伸缩的数组
- 标准库提供的一个允许增长和缩小长度的类似数组的集合类型
## 所有权
- 代码块拥有资源时,被称为所有权。
- 代码块创建一个包含资源的对象。
- 当控件到达末尾时,对象将被销毁,资源将被释放
- Rust中,每个值都有一个与之关联的变量,并成为其所有者
- 一次只能有一个所有者
- 当所有者超出范围是,与其关联的值将被销毁
> a被回收,编译直接报错
```rust
//
fn main(){
let a =20;
let b = a;
println!("{}",a)
}
```
>但是 下面这样就不会被回收~~ TODO ?why?
```rust
fn main1(){
let a =20;
let b = a;
println!("{}",b);
println!("{}",a)
}
```
### 所有权和函数
```rust
fn main(){
let s =String::from("SDUSAJDOISAJ IUJODSJAI ");//啥意思?
take_ownership(s);
let ch ='a';
move_copy(ch);
println!("main:{}",ch)
}
fn take_ownership(str:String){
println!("take_ownership:{}",str)
}
fn move_copy(c:char){
println!("move_copy:{}",c)
}
```
-
## 字符
```rust
fn main(){
let ch = 'a';
//let tt = 'abad';//为啥这里会报错,因为char 类型只能是一个字符
move_copy(ch);
move_copy(tt);
}
fn move_copy(str:String){
println!("{}",str)
}
```
### 存放任意字符,斜杠之类的
> \d \q都有问题
>let s =String::from("S/\q\t\nI}POYY?M>NM>M std::io::Result<()> {
fs::write("foo.txt","哈哈哈")?;
Ok(())
}
fn main() {
println!("hello world");
let _ = write_file();
}
```
## 数据类型
|类型 |值 |
|----|----|
|布尔类型|`true` `false`|
|字符类型|单个Unicode类型,存储4个字节|
|数值类型-符号整数|`i8` `i16` `i32` `i64` `isize`|
|数值类型-无符号整数|`u8` `u16` `u32` `u64` `usize`|
|数值类型-浮点数|`f32` `f64`|
|字符串类型-底层不定长类型|`str`|
|字符串类型-字符串切片|`&str`,静态分配,固定大小,不可变|
|字符串类型-堆分配字符串|`String`,可变|
|数组|固定大小,且元素都同类型,`[T;N]`|
|切片|引用一个数组的部分数据,并且不需要拷贝,`&[T]`|
|元组|固定大小的有序列表,元素都有自己的类型,通过解构或者索引来获取值|
|指针|最底层的裸指针,`*const T` `*mut T`,但解引用它们是不安全的,必须放到`unsafe`块里|
|函数|具有函数类型的变量实质上是一个函数指针|
|元类型|即`()`,其唯一值也是`()`|
### 标量类型
- `整型`。没有小数部分的数字,默认`i32`
rust中的整型
|长度|有符号|无符号(负数)|-(2n-1 -1)|
|----|-----|-----|----|
|8-bit|`i8`|`u8`||
|16-bit|`i16`|`u16`||
|32-bit|`i32`|`u32`||
|64-bit|`i64`|`u64`||
|arch|`isize`|`usize`||
|||||
`isize`和`usize` 类型依赖计算机架构,64位是64位,32位是32位
rust中的整型字面值
|数字字面值| 例子 |
|---- |---- |
|`Decimal`|`98_222`|
|`Hex`|`0xff`|
|`Octal`|`0o77` |
|`Binary`|`0b1111_0000`|
|`byte` (`u8` only)|b`A`|
**整型溢出**:`u8` 放到0-255值,修改为`256`,被称为`整型溢出`(idnteger overflow)
在 release 构建中,Rust 不检测溢出,相反会进行一种被称为 “two’s complement wrapping” 的操作。简而言之,256 变成 0,257 变成 1,依此类推。依赖溢出被认为是一种错误,即便可能出现这种行为。如果你确实需要这种行为,标准库中有一个类型显式提供此功能,Wrapping。
- `浮点型`。带小数点的数字,有两个原生的浮点数类型`f32`、`f64`,默认`f64`。IEEE-754标准
- `f32` 单精度浮点数
- `f64` 双精度浮点数
```rust
fn main(){
let x = 2.0; // f64
let y:f32= 3.2; //f32
}
```
- `布尔型`。bool
- true
- false
- `字符类`。
- `char`代表Unicode,单个字符,中文或者其他语言的单字
### 复合类型
- tuple `(a,b,c,d)`
- array `[a,b,c,d]`
### 基本类型
|类型|最小值|最大值|值|描述|所属组|
|---|---|---|---|---|---|
|array||||1||
|bool||||||
|char||||||
|f32||||||
|f64||||||
|fn||||||
|i8||||||
|i16||||||
|i32||||||
|i64||||||
|i128||||||
|isize||||||
|never||||||
|pointer||||||
|reference||||||
|slice||||||
|str||||||
|tuple||||||
|u8||||||
|u16||||||
|u32||||||
|u64||||||
|u128||||||
|unit||||||
|usize||||||
> https://doc.rust-lang.org/nightly/std/primitive.i8.html
### 数字转为其他类型
## rustup
Command | Description
----------------------------------------------------------- | ------------------------------------------------------------
`rustup default nightly` | Set the default toolchain to the latest nightly
`rustup target list` | List all available targets for the active toolchain
`rustup target add arm-linux-androideabi` | Install the Android target
`rustup target remove arm-linux-androideabi` | Remove the Android target
`rustup run nightly rustc foo.rs` | Run the nightly regardless of the active toolchain
`rustc +nightly foo.rs` | Shorthand way to run a nightly compiler
`rustup run nightly bash` | Run a shell configured for the nightly compiler
`rustup default stable-msvc` | On Windows, use the MSVC toolchain instead of GNU
`rustup override set nightly-2015-04-01` | For the current directory, use a nightly from a specific date
`rustup toolchain link my-toolchain "C:\RustInstallation"` | Install a custom toolchain by symlinking an existing installation
`rustup show` | Show which toolchain will be used in the current directory
`rustup toolchain uninstall nightly` | Uninstall a given toolchain
`rustup toolchain help` | Show the `help` page for a subcommand (like `toolchain`)
`rustup man cargo` | \(*Unix only*\) View the man page for a given command (like `cargo`)
## Cargo
- https://rustlang-cn.org/office/rust/cargo/getting-started/installation.html
### 安装Cargo
> curl https://sh.rustup.rs -sSf | sh
如果顺利则:
> Rust is installed now. Great!
### Cargo 第一步
创建项目:
> cargo new helloworld
build
>cargo build
运行
>./target/debug/helloworld
cargo run
>cargo run
cargo doc --open 生成并打开一个文档,构建所有本地依赖提供的文档。帅!
>cargo doc --open
### cargo 指南
为什么会有cargo:
- 引入两个带有各种程序包信息的元数据文件
- 获取和构建项目依赖
- 正确的构建参数调用rustc 和其他构建工具
- 引入惯例使得rust程序包开发管理更加容易
已存的cargo项目
```cmd
git clone xx
cd xx
cargo build
```
一个cargo依赖如何添加
```toml
[dependencies]
time="0.1.12"
```
cargo build 会获取新的依赖以及依赖的依赖,一并编译。并且更新Cargo.lock文件
cargo update 更新依赖
cargo 项目结构:
```mk
.
├── Cargo.lock 具体依赖信息,cargo维护,不应该手动修改,可防止.gitignore文件
├── Cargo.toml 广义上秒数项目的依赖文件,开发者编写
├── benches 性能评估
│ └── large-input.rs
├── examples 示例目录
│ └── simple.rs
├── src 源码
│ ├── bin
│ │ └── another_executable.rs
│ ├── lib.rs 库文件
│ └── main.rs 默认可执行文件源代码
└── tests 单元测试
└── some-integration-tests.rs
```
### cargo toml 清单文件
```toml
[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name "]
[dependencies]
# 指定依赖仓库
rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
# 解决指定版本,没多卵用。
rand = { git = "https://github.com/rust-lang-nursery/rand.git", rev = "9f35b8e" }
```
cargo update 更新所有依赖
cargo update -p rand 仅更新rand
### cargo test
- `src` 目录下每个文件中的 `tests/`目录,单元测试
- `test/`目录是集成风格的测试
- `cargo test` 会运行额外的检查
- 参考文档https://doc.rust-lang.org/book/testing.html
可执行指定参数测试,将测试名称含有foo的所有测试
> carto test foo
### cargo 持续集成
#### Travis CI 测试项目
- 测试所有三个发布通道
- 任何nightly构建中断将不会使整体构建失败
- 参考 Travic CI Rust documentation https://docs.travis-ci.com/user/languages/rust/
```yml
language:rust
rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- rust :nightly
```
#### GitLab CI
- stable 通道 和 nightly 通道测试
- 任何nightly构建中断将不会使整体构建失败
- Gitlab CI https://docs.gitlab.com/ce/ci/yaml/README.html
```yml
stages:
- build
rust-latest:
stage:build
image:rust:latest
script:
- cargo build --verbose
- cargo test --verbose
rust-nightly:
statge:build
image:rustlang/rust:nightly
script:
- cargo build --verbose
- cargo test --verbose
allow_failure:true
```
#### build.sr.ht
- 确保将``和``改变为要克隆和已克隆的目录。
- 将会在stable和nightly通道测试和构建文档
- 但是任何nightly构建中断将不会使整体构建失败
- 参考builds.sr.ht documentation https://man.sr.ht/builds.sr.ht/
```yml
image: archlinux
packages:
- rustup
sources:
-
tasks:
- setup: |
rustup toolchain install nightly stable
cd /
rustup run stable cargo fetch
- stable: |
rustup default stable
cd /
cargo build --verbose
cargo test --verbose
- nightly: |
rustup default nightly
cd /
cargo build --verbose ||:
cargo test --verbose ||:
- docs: |
cd /
rustup run stable cargo doc --no-deps
rustup run nightly cargo doc --no-deps ||:
```
#### cargo构建缓存
- 同一个工作区所有项目之间,共享构建信息
- 第三方工具sscache https://github.com/mozilla/sccache ,可以得到不共享效果
- 参考 https://rustlang-cn.org/office/rust/cargo/guide/build-cache.html
### cargo 依赖指定
- 更多详细信息 https://rustlang-cn.org/office/rust/cargo/reference/specifying-dependencies.html
```toml
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand" }
# 指定分支
[dependencies]
rand = { git = "https://github.com/rust-lang-nursery/rand", branch = "next" }
# 路径依赖指定
[dependencies]
hello_utils = { path = "hello_utils" }
# 发布cargo箱子
[dependencies]
hello_utils = { path = "hello_utils", version = "0.1.0" }
```
### cargo 清单格式 TODO
- https://rustlang-cn.org/office/rust/cargo/reference/manifest.html
- [package]
- [profile]
### cargo 环境变量 TODO
- https://rustlang-cn.org/office/rust/cargo/reference/environment-variables.html
### cargo 构建脚本
- https://rustlang-cn.org/office/rust/cargo/reference/build-scripts.html
### cargo 发布依赖到crates.io
### cargo 词汇表
- https://rustlang-cn.org/office/rust/cargo/appendix/glossary.html
### cargo 错误
> Blocking waiting for file lock on the registry index
解决: rm -rf ~/.cargo/registry/index/*
## rust redis
- https://crates.io/crates/redis
- https://docs.rs/redis/0.11.0-beta.2/redis/
## rust mongo
- https://crates.io/crates/mongodb