下载rust: curl https://sh.rustup.rs -sSf | sh
更新rust: rustup update
删除rust: rustup self uninstall
查看本地文档: rustup doc
编译文件: rustc 源文件名,只适合简单的rust程序
使用cargo创建项目: cargo new 项目名
构建并运行: cargo run 构建: cargo build 为发布构建: cargo build --release
检查代码,确保能够通过编译,不会产生任何可执行文件: cargo check
参考《Rust权威指南》
let
关键字
mut
关键字可以使变量可变mut
关键字,常量永远都是不可变的const
关键字UPPER_SNAKE_CASE
命名规则shadow
之前声明的同名变量let
声明的同名新变量,类型可以与之前的变量不同let
声明的新变量也是不可变的let
关键字,那么重新给非mut的变量赋值会导致编译时的错误-(2^n-1)~2^(n-1)-1
0~(2^n)-1
isize/usize
类型的位数由程序运行的计算机架构所决定长度 | 有符号 | 无符号 |
---|---|---|
8bit | i8 | u8 |
32bit | i32(默认) | u32 |
16bit | i16 | u16 |
64bit | i64 | u64 |
128bit | i128 | u128 |
arch | isize | usize |
21u8
,代表u8
类型的21
字面值 | 例子 |
---|---|
十进制 | 100_000 |
十六进制 | 0xcc |
八进制 | 0o56 |
二进制 | 0b1010_0101 |
byte(u8) | b’A’ |
u8
的范围是0~255
,倘若将其设为256
panic
环绕操作
,即256
变为0
let t:(i32,&str,char) = (500,"zhangsan",'A');
let (x,y,z) = t;
let a = t.0;
let arr:[i32;3] = [1,2,4];
let arr = [5;3];
相当于let arr = [5,5,5];
println!("{}",arr[0]);
fn
关键字snake case
命名规范,所有字母都是小写,字母之间用下划线隔开 fn product(id:i32,name:&str) {}
->
后面声明函数的返回值类型,返回值不可命名return
关键字,并指定一个值,大多数函数都是默认使用最后一个表达式作为返回值if
表达式允许根据条件(必须是bool类型)执行不同的代码分支else if
,应用match
重构代码if
是一个表达式,所以可以将其放在let语句中等号左边的位置
let num = if true {4} else {5};
fn main() {
let mut num = 0;
let res = loop {
num +=2;
if num == 10 {
break num * num;
}
};
println!("{}",res);
}
fn main() {
let mut num = 5;
while num != 0 {
println!("{}", num);
num -= 1;
}
println!("end")
}
fn main() {
let arr = [1, 2, 4, 56, 7];
for n in arr.iter() {
println!("{}", n);
}
for num in (1..4).rev() {
println!("{}",num);
}
}
先进后出
分配
let s1 = String::from("zhangsan"); // 失效
let s2 = s1;
drop
函数,并将变量使用的heap内存释放二次释放
这个bug
let s1 = String::from("zhangsan");
let s2 = s1.clone();
println!("{},{}",s1,s2);
fn main() {
let mut s = String::from("rust");
let size = get_size(&mut s);
println!("{}",size);
}
fn get_size(s:&mut String) -> usize {
s.push_str(" gogogog!");
s.len()
}
let mut s = String::from("rust");
{
let s3 = &mut s;
println!("{}", s3);
}
let s1 = &mut s;
// let s2 = &mut s; // error
println!("{}", s1);
&str
)是指向字符串中一部分内容的引用
[开始索引..结束索引]
,前包含后不包含 fn main() {
let s = String::from("hello rust");
let b = &s[..5]; // hello
let e = &s[6..]; // rust
let a = &s[..]; // hello rust
println!("{},{},{}", b, e, a);
}
struct
关键字,并为其命名{}
内为所有字段定义类型和名称 fn main() {
struct User {
id:i32,
name:String,
age:u8,
}
}
fn main() {
let mut u = User {
id:1,
name:String::from("zhangsan"),
age:18,
};
}
fn get_info(id:i32,name:String,age:u8) -> User {
User {
id,
name,
age,
}
}
println!("{}",u.name);
let u2 = User {
id: 2,
name: String::from("lisi"),
..u // 相同的值可以用此表达式代替
};
strcut User(i8,i32,i64);
&self
也可以获得其所有权或可变借用 #[derive(Debug)] // 调试模式
struct Oblong {
width: u32,
length: u32,
}
impl Oblong { // 定义方法
fn area(&self) -> u32 {
self.length * self.width
}
}
fn main() {
let o = Oblong {
width: 34,
length: 56,
};
println!("{}", o.area());
println!("{:#?}", o); // 打印结构体
}
String::from
)
impl Oblong {
fn square(size: u32) -> Oblong {
Oblong {
width: size,
length: size,
}
}
}
fn main() {
let oo = Oblong::square(14);
println!("{:#?},{}", oo,oo.area())
}
// 创建枚举值
enum IpAddrKind {
V4,
V6
}
let ip_addr = IpAddrKind::V6; // 获取枚举值
enum Country {
China(String),
USA(String),
India(String)
}
impl Country {
fn province(&self) {}
}
fn main() {
let c = Country::China(String::from(""));
c.province();
}
enum Option<T> {
Some(T),
None,
}
let res = Some(10);
let res = Some("rust");
let res:Option<u8> = None;
enum RMB {
fen,
jiao,
yuan(String),
}
fn price(r: RMB) -> u8 {
match r {
RMB::fen => 1,
RMB::jiao => 10,
RMB::yuan(goods) => {
println!("{}", goods); // 取值
100
},
}
}
fn price_ignore(r: RMB) -> u8 {
match r {
RMB::fen => 1,
_ => 0,
}
}
fn price_if_let(r: RMB) -> u8 {
if let RMB::fen = r {
println!("fen");
1
} else {
println!("nil");
0
}
}
fn main() {
println!("{}", price(RMB::yuan(String::from("apple"))));
}
package
:cargo的特性,可以构建、测试以及共享crate
Cargo.toml
,描述如何构建crates1或0
个library cratesrc/bin
,每个文件是单独的binary cratecrate
:是一个模块树,可以产生一个library或可执行文件
module
、use:控制代码的组织、作用域以及私有路径
mod father{
mod son {
fn eat() {}
}
mod girl{
fn sleep() {}
}
}
pub
关键字可以将某些条目标记为公共的path
:为struct、function、module等条目命名的方式
::
隔开cargo的惯例
src/main.rs
src/lib.rs
use
关键字将路径引入到作用域内,仍然遵循私有性规则路径相同的部分::{路径不同的部分}
use std::cmp::Ordering;
use std::io;
use std::io::Write;
use std::{io,cmp::Ordering};
use std::io::{self,Write};
Vec
,由标准库提供,可以存储多个值
let mut v:Vec = Vec::new();
let v = vec![1,23,45];
v.push(100);
fn main() {
let v = vec![1,2,46,8];
let t = &v[0];
println!("the get number is {}",t);
mathc v.get(1) {
Some(t) => println!("the get number is {}",t),
None => println!("none"),
}
}
&str
let s = String::from("rust");
,::
表示from是string类型下的函数let s = "rust".to_string();
,创建Stringpush_str()
,将一个字符串切片附加到String
let mut s = String::from("rust"); s.push_str("gogogo");
push
,将单个字符附加到String+
,拼接字符串format!()
,拼接字符串Vec
的包装for s in ss.chars() {}
for s in ss.bytes() {}
use std::collections::HashMap; // 导入
// 格式:`HashMap`,键值对的形式存储数据,所有的k/v类型必须相同
fn main() {
let mut h:HashMap<String,u32> = HashMap::new(); // 创建空hashmap
h.insert(String::from("zhangsan"),18);// 添加数据,若key已存在则用新v覆盖旧v
h.entry(String::from("zhangsan")).or_insert(666); // 添加数据,key已存在不做任何操作,不存在则插入新的v
let name = vec![String::from("zhangsan"),String::from("lisi")];
let age = vec![19,29];
let person:HashMap<_,_> = name.iter().zip(age.iter()).collect(); // 创建hashmap
let n = String::from("zhangsan");
match person.get(&n) { // 获取值
Some(age) => println!("{}",age),
None => println!("nil"),
}
}
Result
use std::fs::File;
fn main() {
let f = File::open("a.txt");
let file = match f {
Ok(file) => file,
Err(error) => panic!("{}", error),
};
let f = File::open("a.txt").unwrap(); // 类型match,不可自定义错误信息
let f = File::open("a.txt").expect("not found"); // 同上,可以自定义错误描述
read()
}
// ?传播错误的一种方式,只能用于返回Result的函数
// 若Result是OK,ok中的值就是表达式的值,然后继续执行程序
// 若Result是Err,Err就是整个函数的返回值,就像使用了return
fn read() -> Result<String, io::Error> {
let mut s = String::new();
File::open("b.txt")?.read_to_string(&mut s)?;
Ok(s)
}
panic!
[profile.release] panic='abort'
fn func_name(field:T) -> T {}
:函数中定义泛型struct struct_name {f1:T,f2:T}
:结构体中定义泛型impl struct_name
impl struct_name
// 只有方法签名,没有具体实现
// 可以有多个方法,每个方法签名占一行,以:结尾
// 实现该trait的类型必须提供具体的方法实现
pub trait Person {
fn get_age(&self) -> String;
fn get_name(&self) -> String {
String::from("get_name")
}
fn get_info(&self) -> String {
format!("{}:{}",self.get_age(),self.get_name())
}
}
pub struct Zhangsan {
pub name: String,
pub age: u8,
}
impl Person for Zhangsan {
fn get_info(&self) -> String {
format!("{}:{}", self.name, self.age)
}
}
fn func_name(t:impl Person) {}
fn func_name(item:T) {}
fn func_name(item:T) {}
fn func_name(item:T) where T:Person+Display {}
fn func_name() -> impl Person {}
'
开头,通常是'a
&
之后,使用空格将标注和引用类型分开fn fn_name<'a>(x:&'a str,y:&'a mut str) -> &'a str {}
'a
的生命周期实际是:x和y两个生命周期中较小的那个#[test]
即可变为测试函数assert!
检查测试结果,true为测试通过,false会调用panic!测试失败assert_eq!
与assert.ne!
测试是否相等
assert!(false,"error message"); assert_eq!(1,2,"not equal");
#[should_panic(expected="")]
,验证错误处理的情况cargo test
后的参数,如cargo test --help
cargo test
后跟--
的参数,如cargo test -- --help
,针对二进制文件--test-threads
,控制线程数--show-output
,在成功的情况下也输出打印的内容#[ignore]
标记cargo test -- --ignored
#[cfg(test)]
标注cargo test 函数名
cargo test --test 文件名
next()
let closure = |num:u8| {println!("{}",num);};
//!
编写抬头///
格式,支持markdown语法cargo doc --open
生成文档并打开Deref
和Drop
两个traitderef coercion
就会自动发生std::mem::drop
函数,来提前drop值std::rc::Rc
Rc::clone(&a)
,增加引用计数RC::Strong_count(&a)
,获得引用计数thread::spawn
Mutex::new(data)
来创建mutex_
,会匹配到任何东西,不会绑定到变量,通常用于match的最后一个arm,或用于忽略某些值|
语法,可以匹配多种模式..
匹配某个范围的值fn main() {
let x = 1;
match x {
1|2 => println!("ok"),
3..=5 => println!("3,4,5"),
'a'..='c' => println!("a,b,c"),
_ => println!(“error”),
}
}
*mut T
,*
是类型的一部分*const T
,指针在解引用之后不能直接对其进行赋值 trait Iterator {
type Item;
fn next(&mut self) -> Option<self::Item>;
}
type Name = String;
!
表示,其在不返回的函数中充当返回类型fn get_name() -> !{}