RUST
[toc]
简介
介绍
- 开始是私人项目,专注于安全。后公司资助,2015年发布第一版。
- Rust 程序设计语言 简体中文版
- 官方网址
环境搭建
ubuntu
$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh |
windows:下载链接
hello-world
- 建立工程:
cargo new hello
//hello/src/main.rs |
- 运行:
cargo run
cargo
| 命令 | 说明 |
|---|---|
| new | 创建工程,cargo new project–lib创建库, cargo new --lib libname |
| run | 运行工程,在项目目录下运行:cargo run |
| build | 编译工程 |
| check | 检查工程 |
| test | 测试 |
基本概念
基本属性
- 变量定义:
let name: type
let a =1;println!("a={}",a);//不可变变量 |
| 类型 | 说明 |
|---|---|
| 可变性 | 默认不可变:let a=1;可变: let mut a=1; |
| 常量 | const MAX_POINTS:u32=10000; |
| 隐藏 | 定义重名变量,则会覆盖前一个let a=1;let a:f32=1.1; |
数据类型
- rust是静态语言,在编译前要确定变量类型,编译器有自动推导的能力。
| 数据类型 | 说明 |
|---|---|
| bool | let a:bool=true;let b:bool=false; |
| char | 字符型是32位的,与其他语言不同,所以可以是一个汉字let a='a';let b='一'; |
| 数字 | i:8,16,32,64;u:8,16,32,64;f:32,64;let c:i8=-11; |
| 数组 | 方括号[type;size]其中size也是数组类型的一部分let arr:[u32;5]=[1,2,3,4,5];println!("arr[0]={}",arr[0]); |
| 自适应类型 | isize,usize大小根机器位数有关println!("max={}",usize::max_value()); |
| 复合数据类型 | 说明 |
|---|---|
| 元组 | 圆括号let tup:(i32,f32,char)=(-3,3.2,'123');let (x,y,z)=tup; |
| 结构体 | |
| 枚举 | |
| 字典 |
字符串
| 操作 | 说明 |
|---|---|
| 创建空字符串 | let mut s=String::new(); |
| 创建有初值 | let mut s=String::from("hello");通过字面值 let mut s="hello".to_string(); |
| 更新 | push_str:s.push_str(" world");s.push_str(&s0);push: s.push('!')只能添加一个字符+: let s3=s1+&s2;,s1所有权给了s3format!: let s=format!("{}-{}",s1,s2);不会获取所有权 |
| 索引 | String:let s2=s[0];报错,rust不支持被索引,防止utf8边界错误str: let s="你好";let h=&hello[0..3];,边界不同也会报错 |
| 遍历 | chars:for c in s.chars(){println!();}bytes: for c in s.bytes(){println!();} |
| 析构 | 离开作用域会调用drop,释放内存 |
- 单引号:字符
- 双引号:表示引用
切片slices
- 字符串
let s1='hello'; //字面值,不可变 |
- 数组
let a = [1,2,3,4,5]; |
结构体
| 操作 | 说明 |
|---|---|
| 定义 | struct User{name:String,count String,nonce:u64,active:bool} |
| 实例 | let mut xiao=User{name:String::from("xiao"),count:String::from("8454"),nonce:1000,active:true,} |
| 修改字段 | 前提是mut可变变量xiao.nonce=2000; |
| 参数名字和字段名同名时可简写 | let name=String::from("xiao");let count=String::from("80808");nonce=1000;active=true;let xiao=User{name,count,nonce,active}; |
| 从其他结构体创建实例 | let xiao2=User{name:String::from("xiao2"),..xiao};//此时xiao被借用 |
| 元祖结构体 | 字段没有名字,圆括号struct Point(i32,i32); let a=Point(10,20);println!("a.x={},a.y={}",a.0,a.1); |
| 没有任何字段的类单元结构体 | struct A{}; |
| 打印结构体 | #[derive(Debug)]println!("xiao={:?}",xiao);println!("xiao={:#?}",xiao); |
- 方法
|
枚举
| 操作 | 说明 |
|---|---|
| 定义方式一(C语言方式) | enum IpAddr{V4,V6}; struct Ip{kind:IpAddr,addr:String} let ip1=Ip{kind:IpAddr::V4,address:String::from("127.0.0.1"),}; |
| 定义方式二(推荐) | enum IpAddr{V4(String),V6(String),}; let i=IpAddr::V4(String::from("127.0.0.1")) |
| 定义不同类型 | enum IpAddr{V4(u8,u8,u8,u8,),V6(String),}; let ip1=IpAddr::V4(127,0,0,1)); let ip2=IpAddr::V6(String::from("::1"))); |
- 用法
enum Message{ |
- 方法及模式匹配
impl Message{ |
Option
- 标准库定义的一个枚举,原始形式:
enum Option<T>{Some(T),None,},T表示泛型
fn main(){ |
vector
| 操作 | 说明 |
|---|---|
| 创建空的vector | Vec<T>let mut v:Vec<i32>=Vec::new(); |
| 创建包含初值的vector | Vec<T>let mut v=vec![1,2,3]; |
| 压栈 | v.push(1); |
| 丢弃vector | 会丢弃全部元素,{let v1=vec![1];} |
| 读取 | 方式一:let one:&i32=&v[0];方式二(推荐): match v.get(1){Some(value)=>println!("two={}",value),_=>{},} |
| 遍历 | 不可变遍历for i in &v{println!("i={}",i);}可变遍历 for i in &mut v{*i+=1;} |
| 存储不同的类型 | 利用枚举存储不同的类型,enum Context{Text(String),FLoat(f32),Int(i32),};let c=vec![Context::Text(String::from("1")),Context::Float(1.2),Int(12),]; |
hashmap
HashMap<Key,Value>
| 操作 | 说明 |
|---|---|
| 导入包 | use std::collections::HashMap; |
| 创建 | 方式一:let mut map:HashMap<String,i32>=HashMap::new();方式二: let keys=vec![String::from("1")];let values=vec![1];let map:HashMap<String,i32>=kes.iter().zip(values.iter()).collect(); |
| 直接插入 | map.insert(String::from("1"),1); |
| 不存在时插入 | map.entry(String::from("2")).or_insert(2); |
| 更新插入 | let count=map.entry(String::from("1")).or_insert(0);*count+=1; |
| 读取 | let k=String::from("1");if let Some(v)=map.get(&k){println!("v={}",v);} |
| 遍历 | for (k,v) in &map{println!("{}:{}",k,v);}println!("{:?},map"); |
函数
- 函数定义:
fn f1(){} - 函数调用
- 参数传入:
fn f1(a:i32,b:u32){}参数定义时需要类型,无法自动推导 - 返回值:
- 方法一:
fn f1(a:i32,b:i32)->i32{return a+b;} - 方法二:
fn f1(a:i32,b:i32)->i32{a+b}语句没有返回值,所以不能有分号 - 表达式是有返回值的:
let y = {let a=1;a+1};
- 方法一:
注释
//
控制流
if
let y=1; |
loop
let mut counter = 0; |
while
let mut i=0; |
for
let arr:[u32;5]=[1,2,3,4,5]; |
match
- 类似于switch
match a{ |
所有权
- rust使用所有权机制管理内存,编译器在编译就会根据所有权对内存的使用进行检测
堆和栈
- 编译的时候,数据类型大小是固定的,就是分配在栈上,反之就是堆上
let x:i32=1; // 栈上 |
变量作用域
- 作用域范围:
{}
函数的作用域:
fn ownership(s:String){ |
移动和拷贝
- 堆上的移动后原来变量无效,反之多次释放同一块内存;
let s1=String::from("hello"); // string类型长度不确定,堆上 |
- 堆上的克隆相当于深拷贝;
let s1=String::from("hello"); // string类型长度不确定,堆上 |
- 栈上的拷贝可以继续使用,或者实现了copy特征的类型也无需clone,包括:整型、浮点、布尔、字符、元组;
let a=1; |
引用和借用
- 引用:
& name - 解引用:
* name,取里面的内容 - 借用:
&mut name - 创建一个指向值的引用,但并不拥有这个值,所以离开作用域不会被释放;
fn calcute_len(s:&String)->usize{ //引用 |
- 可变引用
fn modify_s(s:&mut String){ //修改时需要借用 |
- 借用后不能再使用引用
let mut s1 = String:from("hello"); |
- 悬垂引用(Dangling References)
fn main(){ |
包
- 包(Packages): Cargo 的一个功能,它允许你构建、测试和分享 crate。
- Crates :一个模块的树形结构,它形成了库或二进制项目。
- 模块(Modules)和 use: 允许你控制作用域和路径的私有性。
- 路径(path):一个命名例如结构体、函数或模块等项的方式
模块
- mod模块创建默认是私有的,不能直接通过路径调用,需要声明pub
mod factory{ |
crate
- 创建库:
cargo new --lib mylib
//vi mylib/src/factory.rs |
- 导出模块
//vi mylib/src/lib.rs |
- 配置模块:Cargo.toml
... |
- 使用库
//vi src/main.rs |
mod的结构体
mod modA{ |
- 访问上一级的模块
pub mod modB{ |
外部库
- 引入rustcrypto,在Cargo.toml添加引用
... |
- 在代码中引用
//src/main.rs |
- 执行
cargo run时,相应的库会自动下载和编译。
错误
- rust的错误分为:
- 可恢复错误:用户报告的错误和重试操作是否合理,用枚举
Result<T,E>实现 - 不可恢复错误:通过
panic! unwrap expect实现
- 可恢复错误:用户报告的错误和重试操作是否合理,用枚举
panic!
fn main(){ |
RUST_BACKTRACE
RUST_BACKTRACE=1 cargo run执行时会打印调试堆栈,非0即可
Result<T,E>
- 原型
enum Result<T,E>{ |
use std::fs::File; |
- 简写方式
fn main(){ |
错误传递
use std::io; |
测试
- 执行
cargo new --lib mylib
//mylib/src/animal.rs |
- 执行测试:
cargo test
泛型
- 泛型是具体类型或其他属性的抽象替代。减少代码重复
- 泛型不会导致程序性能损失,rust在编译过程会对泛型进行单态化,转化为特定代码。
使用泛型
- 函数定义
//泛型满足特征:PartialOrd可排序,Copy有copy特征 |
- 结构体
|
- 枚举
enum Option<T>{ |
- 方法
struct Point<T>{ |
特征trait
- trait 告诉 Rust 编译器某个特定类型拥有可能与其他类型共享的功能。类似于接口interface
- 通过trait以抽象的方式定义共享的行为
- trait bounds指定泛型是任何拥有特定行为的类型
使用
- 定义
pub trait GetInfo{ |
- 实现
|
- trait作为参数
fn print_info(item:impl GetInfo){ |
- 默认实现
trait SchoolName{ |
