Rust 语法
基础
- 输出
println!("a is {0} and b is {1}", a,b)
println!("struct can be {:#?}", st1)
- 输出
use std::io::stdin;
let mut str = String::new()
stdin().read_line(&mut str).unwrap();
- 命令参数
let args = std::env::args()
for i in args{}
- 变量 let
- 变量不变类型
- 修改要加mut
- 重影 重新使用变量名
- 常量 const 只能赋值一次
- 静态 static
- 程序内共享
- 可以加mut (不安全)
- 数据类型
- 整数
- (u/i) + (8/16/32/64/128)
- 1_000_000 0xff 0o77 0b1111_0000 b'A'
- 不支持 ++ --
- 浮点
- f32 f64
- .sin/cos/tan/sqrt/ln/power(4)
- 布尔
- true false
- 与01不能直接自动转换
> >= == != ! && || ^ & |
- 字符 char utf-8
- 字符串常量 &str
let s1: &str = "abc";
let s2: String = String::from("abc");
- push push_str len eq chars().nth(2).unwrap()
&s[0..3]
- 元组
(i32, f64, char)
- tup.0/1/2/3 不能用
[0]
- 数组
[i32; 5]
arr[0/1/2]
.len()
iter()
- 切片
&s[1..]: &str
&arr[..4]: &[i32]
- 本质是对数据的部分引用
- 字符串常量本质就是切片引用类型
- 整数
- 流程控制
if bool {}else if bool {} else {}
bool不写括号let num = if a>0 {1} else {-1}
没有三元match op {0=>{}, 1|-1 =>{}, _=>{}}
while bool {}
for i in 迭代器{}
非迭代的for用while1..5
arr.iter()
0..arr.len()
loop{}
无限循环等breaklet v = loop{ if arr[i]>0 {break i;}}
支持表达式
函数
rust
// 声明
fn func(a: i32, b: i32)->i32{
// a+b
return a+b;
}
// 函数表达式
let y = {
let a = 2;
let b = 2;
a+b+3
};
// 函数变量
let mut fun: fn();
fun = func;
fun();
// 闭包 lambda 匿名函数
let lb = |a: i32, b: i32|->i32{
return a+b;
}
let lb = |x: i32| x+1;
所有权
- 理念
- 变量是数据对象的所有者
- 一个数据只有一个所有者
- 所有者不可用时数据销毁
- 概念
- 转移
let y = x
后x失去数据 适用于引用类型 - 复制 x仍保有数据 适用于数字 布尔 字符 相应元组
- 引用
let s2 = &s1
借用数据 数据只有一份- 常用于不支持复制的数据传递
- 垂悬引用 借用失去的数据 不允许 如函数返回变量引用
- 可变引用
&mut
可改变指向的地址 - 解引用
*
可改变该地址下本体值 实现交换函数
- 转移
- 函数相关
func(a)
a根据类型发生转移和复制func(&a)
借用 不失去所有权return b;
返回时给出所有权return &b;
垂悬引用
复合类型
结构体
- 定义和实例化
struct Site{domain: String}
let site = Site {domain: String::from("abc")}
name: name
可以简写let obj2 = Obj {name, ..obj1}
继承
- 所有权
- 字段赋值类似变量 会发生转移或复制
- 字段若采用引用类型会报错 例如
&str
- 需要加上生命周期标识符
<'a>
&'a str
- 需要加上生命周期标识符
- 结构体方法
impl Site{}
fn plus(&self)->i32{self.ip + self.port}
self不用类型site1.plus()
- 元组结构体
struct Color(u8,u8,u8)
let black = Color(0,0,0)
black.0/1/2
- 单元结构体
struct Unit
枚举
- 定义和实例化
enum Color{Red,Green,Blue}
let color = Color::Red
enum Book{Idx(u32),Name(String)}
let book = Book::Idx(100)
let book = Book::Name(String::from("hello"))
enum Book{Site{ip:String,port:u32},Student{name:String}}
let ebook = Book::Site{ip:String::from("fdsf"),port:2077}
- match
match book{}
Book::Idx (index)=>{}
Book::Site {ip}=>{}
- if let
if let Book::Site {ip} = book{println!("",ip)}
else{}
- 枚举方法
impl Book{}
fn setBook(&mut self){*self = Book::Name(String::from("hello"))}
泛型
- 泛型函数
fn func<T>(arr: &[T])-> &T{&arr[arr.len()-1]}
- 泛型结构体
struct Point<T>{x:T,y:T}
struct Point<T1, T2>{x:T1,y:T2}
let point = Point::<i32>{x:1,y:2}
- 泛型枚举
enum Shape<T>{Rect(T,T),Cube(T,T,T)}
let s = Shape::Cube(1,1,1)
- impl 泛型
impl<T> Point<T>{}
第一个t表示要用泛型 第二个t表示类型fn get_x(&self) -> &T{&self.x}
impl<A,B> Data<A,B>{}
fn mix<C,D>(self, other: Date<C,D>)->Data<A,D>{Data{x:self.x,y:other.y}}
错误处理
- 不可恢复错误
panic!("error")
输出错误停止运行.unwrap()
.expect("wrong")
将可恢复错误转不可恢复 停止程序
- 可恢复错误
- Result
enum Result<T,E>{Ok(T),Err(E)}
match res{}
Ok(val)=>{}
Err(err)=>{}
- 传递
-> Result<i32,&'static str>
return Result::Ok(a)
return Result::Err("errer")
- 若当前函数返回值类型与调用函数一致 可以用?直接传递错误
let a = func(x)?;
- 错误类型
Err(e)=>{match e.kind(){}}
- Result
- Null Option
- rust任何变量都不能是Null 空指针 空引用
enum Option<T>{None,Some(T)}
some 表示有值fn func()-> Option<usize>{}
return Option::Some(i)
return Option::None
if let Some (i) = func() {println!("{}",i)}else{}
let opt = func().except("none")
也可以直接停止
模块
- 箱 包 模块
mod
模块类型pub
默认私有 使之公有super
类似..
use
把某嵌套模块下的东西引入当前作用域
- 多文件程序
modu.rs
pub fn func(){}
main.rs
mod modu;
fn main(){modu::func();}
- cargo
cargo new name
init
在当前目录新建build
run
doc
库名称 = "0.1.1"
extern crate rand
use rand::Rng;
接口 trait
- 定义和实现
trait Tools {}
fn less(&self, b: &Self)-> bool
&self自身和&Self同类impl Tools for Structure{}
fn less(&self, b: &Structure)->{true}
- 一个类多种接口 一个impl只能实现一种接口 并且只能写接口里的方法
- 默认特性 可以在定义的时候写上默认函数实现 impl里面没写的话就会调用默认
- 接口做参数
fn func(arr: &mut [&impl Tools])
impl Tools for f64{}
func(&mut arr64)
- 泛型函数
fn func<T: Tools>(a:T){}
用于impl了Tools的类的对象 多参数类型要一样
- 接口叠加类型
fn func(a: impl Tools1 + Tools2){}
fn func<T: Tools1+Tools2, U: Tools2+Tools3>(t:T, u:U){}
fn func<T, U>(t:T, u:U)
where T:Tools1+Tools2, U: Tools2+Tools3
- 返回接口
fn func() -> impl Tools{}
- 返回实现了该接口的对象 但只能是一种类型的对象(多条件分支下)
- 有条件的实现
struct A<T>;
trait B{}
impl<T: B> A<T>{}
A类型只有在T实现了B的前提下才能调用impl
文件
- 文件和流
- 文件可以看成一种数据结构
- 流描述的是数据传输
- 读
use std::fs;
use std::io::Read
let txt = fs::read_to_string("./hello.txt").unwrap();
字符串read()
二进制open()
File对象file.read_to_end(&mut u8Vec)
一次性读入
- 写
use std::fs::File
use std::io::Write
``let mut file = File::create(path)
创建/覆写file.write(b"hello")
写入
- 其它模式
use std::fs::OpenOptions
OpenOptions::new().append(true).open(path).write(b"hello")
- read write append create create_new truncate
- 二进制
to_ne_bytes
to_le_bytes
to_be_bytes
cpu字节序 小端 大端 转二进制f64::from__ne/le/be_bytes(buffer)
从二进制读入
- 目录
- 列出
fs::read_dir(path)
i.file_name().to_str()
- 创建
fs::create_dir(path)
fs::create_dir_all(path)
- 删除
fs::remove_dir(path)
fs::remove_dir_all(path)
- 列出
数据结构
- 线性数据结构
- 数组链表 用链表存放数组
- 用固定大小的数组保存元素再把数组像链表一样连起来
- 链表数组 用数组存放链表
- 数组链表 用链表存放数组
- Vec
let vect: Vec<i32> = Vec::<i32>::new()
let vect = vec![1,2,3]
push pop remove(i) append(&mut v2) get_mut
use std::collections::LinkedList/VecDeque/HashMap/BTreeMap/Set/BinaryHeap
- VecDeque
push_back(i)
- LinkedList 链表
- String
数据.to_string()
push('w') push_str("wold")
let s4 = s1 + &s2 + &s3
s4会获得s1的所有权let str = format!("{}年{:02}月{:02}日",y,m,d)
- 截取
&str[1..4]
str.chars().nth(2)
字符
- 长度
.len()
中文长度3str.chars().count()
- HashMap 映射
let mut map = HashMap::<&str, &str>::new()
.insert("name","ok")
.get("name")
- 其它类型需实现Hash Eq两个接口
- BTreeMap 有序映射
- Set
let mut sets = HashSet::<&str>::new()
.insert("h")
- 其它类型需实现Hash Eq(PartialEq)两个接口
- BTreeSet 有序集
- 堆 树状有序数据结构 适用于频繁插入取出的场合
let mut heap = BinaryHeap::<u32>::new()
let heap = BinaryHeap::from(vec)
.push(i) .pop()
for i in heap{}
面向对象
- 类
struct
impl
- 对象
impl
实现new()
方法 返回结构体实例 - 封装
mod
- 继承 结构体嵌套
- 多态
trait
的不同实现
堆内存 Box
- 用于在编译时无法确定大小或生命与函数不同的情况
Box::new(St{})
rust
// 递归嵌套的结构体符合使用条件
struct Link{
val: i32,
next: Option<Box<Link>>
}
fn main(){
let link = Some(Box::new(Link{
val:1,
next:Some(Box::new(Link{
data:2,
next:None
}))
}));
let mut l = &link;
loop{
if let Some(b) = l{
l = &b.next;
}else{
break;
}
}
}
进阶
- Rc 引用计数
let data = Rc::new(St{val: 1})
- 可以让数据被多次克隆 引用数量为1时释放
- 本质为多个引用
- Mutex 互斥锁
let m = Mutex::new(100)
.lock()
.unlock()
在还没解锁的时候会等待
- 运算符重载
impl Add for St{}
fn add(self, ta:Self)->Self{}
Self{a: self.a + ta.a}
- 属性
- 条件编译属性
#[cfg(target_os = "linux")]
#[test]
cfg_attr
- 派生属性 自动为类型生成实现
#[derive(Clone)]
- 诊断属性
#[warn(missing_docs)]
deprecate
标记过时#[must_use]
没用到的元素会警告
- 模块路径属性 确定路径
#[path = "sub_mod/the_mod.rs"]
- 其它属性
- 条件编译属性
- 宏 预定义规则生成代码
- 定义和使用
macro_rules! 宏名 {}
($参数名: 宏参数类型)=>{}
($($x: expr), *)
可变参数个数宏名!()/{}/[]
调用
- 可有多种参数形式 用于实现重载
- 过程宏
- 函数宏 形如函数,并像函数一般调用
- 派生宏 能够为结构体、枚举等实现特征
- 属性宏 用于结构体、字段、函数等,为其指定属性
- 定义和使用
- 不安全领域
unsafe{}
- 使用原始指针
let ptr = 0xABCDEF as *const/mut i32;
let ptr = &mut number as *mut i32;
- 使用不安全的函数和方法
unsafe fn func(){}
定义- 只能在领域内使用
- 直接改变静态变量
static mut num = 100
unsafe{num+=1;}
- 实现不安全的接口
unsafe trait Tool{}
unsafe impl Tool for St{}
- 访问共用体字段
union Num{i: u64, f: f64}
let num = Num{f:3.14159}
unsafe{printfln("{}",num.i)}
- 使用原始指针
多线程
rust
use std::thread;
fn sub(){
for i in 1..5{
println!("sub {}",i);
}
}
fn main(){
// thread::spawn(sub);
thread::spawn(sub).join();
for i in 1..5{
println!("main {}",i);
}
thread::sleep(Duration::from_millis(200))
}
rust
use std::sync::mpsc;
fn main(){
let (sender,recver) = mpsc::channel();
thread::spawn(move ||{
sender.send("hello")
})
println("{}",recver.recv())
}
rust
use std::thread
use std::sync::{Arc, Mutex, mpsc}
fn main(){
let (s1,r1) = mpsc::channel();
let (s2,r2)= mpsc::channel();
let sum = Arc::new(Mutex::new(0_u32));
let copy_1 = sum.clone();
thread::spawn(move ||{
let mut sum value = copy_l.lock().unwrap();
for i in 1..11{ *sum value += i;}
sl.send(0).unwrap();
});
let copy_2 = sum.clone();
thread::spawn (move ||{
let mut sum value = copy 2.1ock().unwrap();
for i in 11..21{*sum value += i;}
s2.send(0).unwrap();
} );
rl.recv().unwrap();
r2.recv().unwrap();
let locked_sum = sum.lock().unwrap();
println!("sum is (]",locked_sum);
}
rust
use std::sync::{mpsc, Arc, Mutex};
use std::thread;
fn main() {
let (s1, r1) = mpsc::channel();
let (s2, r2) = mpsc::channel();
let data = Arc::new(Mutex::new((1_u32, 2_u32)));
let copy_1 = data.clone();
thread::spawn(move || {
let mut data = copy_1.lock().unwrap();
(*data).0 += (*data).1;
s1.send(0).unwrap();
});
let copy_2 = data.clone();
thread::spawn(move || {
let mut data = copy_2.lock().unwrap();
(*data).1 += (*data).0;
s2.send(0).unwrap();
});
rl.recv().unwrap();
r2.recv().unwrap();
let locked_data = data.lock().unwrap();
println!("data =[:?]", locked_data);
}
// 标志互斥锁
let flag = Arc::new(Mutex::new(0));
网络通信
- Tcp
use std::net::TcpStream;
let s = TcpListener::bind("127.0.0.1:8080")
let mut c = TcpStream::connect("127.0.0.1:8080")
let (c,addr) = s.accept()
c.write(b"hello");
while c.read(&buffer)>0{vect.push(buffer[0])}
for c in s.incoming(){}
循环accept
- Udp
let skt = UdpSocket::bind("127.0.0.1:8080")
skt.send_to(b"hello","ip:port")
let (size, addr) = skt.recv_from(buffer)
let (size, addr) = skt.peek_from(buffer)
不会将数据从缓冲中移除
- http
- 用tcp发送含html内容的字符串