fn main() {
println!("Hello, World!");
}
rustc main.rs
.\main.exe
./main
fn main() {}
println!("Hello, World!")
;
结尾rustc 源文件名
rustc main.rs
cargo --version
cargo new hello_cargo
--vcs
这个flagcargo build
cargo run
,编译代码+执行结果
cargo check
,检查代码,确保能通过编译,但是不产生任何可执行文件cargo build --release
建议尽量使用Cargo
use std::io;
use std::cmp::Ordering;
use rand::Rng;
fn main() {
println!("猜数!");
let secret_number = rand::thread_rng().gen_range(1, 101); // [1, 101)
// println!("神秘数字是:{}", secret_number);
loop {
println!("猜测一个数(1~100)");
let mut guess = String::new();
io::stdin().read_line(&mut guess).expect("无法读取行");
println!("你猜测的数是:{}", guess);
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
match guess.cmp(&secret_number) {
Ordering::Less => println!("你猜的数小了"),
Ordering::Greater => println!("你猜的数太大了"),
Ordering::Equal => {
println!("恭喜你,猜中了!!!");
break;
}
}
}
}
let
关键字mut
关键字,就可以使变量可变mut
,常量永远都是不可变的const
关键字,它的类型必须被标注MAX_POINT
const MAX_POINT: u32 = 100_000;
u32
就是一个无符号的整数类型,占据32位的空间Length | Signed | Unsigned |
---|---|---|
8-bit | i8 | u8 |
16-bit | i16 | u16 |
32-bit | i32 | u32 |
64-bit | i64 | u64 |
128-bit | i128 | u128 |
arch | isize | usize |
Number Literals | Exanple |
---|---|
Decimal | 98_222 |
Hex | 0xff |
Octal | 0o77 |
Binary | 0b1111_0000 |
Byte(u8 only) | b’A’ |
i32
f32
,32位,单精度f64
,64位,双精度true
和 false
bool
char
类型被用来描述语言中最基础的单个字符let x := 'z';
let y : char = 'Z';
let z = '';
let tup: (i32, f64, u8) = (500, 6.4, 1);
let tup: (i32, f64, u8) = (500, 6.4, 1);
let (x, y, z) = tup;
println!("{}, {}, {}", x, y, z);
let tup: (i32, f64, u8) = (500, 6.4, 1);
println!("{}, {}, {}", tup.0, tup.1, tup.2);
[类型; 长度]
let a: [i32; 5] = [1, 2, 3, 4, 5];
let a = [3; 5];
它就相当于:let a = [3, 3, 3, 3, 3];
let first = months[0];
let second = months[1];
fn
关键字fn main() {
another_function(5); // arguments
}
fn another_function(x: i32) { // parameter
println!("the value of x is: {}", x);
}
->
符号后边声明函数返回值的类型,但是不可以为返回值命名return
关键字,并指定一个值
fn plus_five(x: i32) -> i32 {
x + 5
}
//
/**/
fn main() {
let number = 3;
if number < 5 {
println!("condition was true");
} else {
println!("condition was false");
}
}
let condition = true;
let number = if condition { 5 } else { 6 };
loop
关键字告诉Rust反复执行一块代码,直到你喊停break
关键字来告诉程序何时停止循环
fn main() {
let mut number = 0;
let result = loop {
counter += 1;
if counter == 10 {
break counter * 2;
}
};
println!("The result is: {}", result);
}
fn main() {
let mut number = 3;
while number != 0 {
println!("{}!", number);
number = number - 1;
}
println!("LIFTOFF!!!");
}
let a = [10, 20, 30, 40, 50];
for element in a.iter() {
println!("the value is: {}", element);
}
for number in (1..4).rev() {
println!("{}!", number);
}
println!("LIFTOFF!!!");
from
函数从字符串字面值创建出String类型let s = String::from("hello");
String::from()
来实现drop()
函数let x = 5;
let y = x;
let s1 = String::from("hello");
let s2 = s1;
drop
函数,并将变量使用的heap内存释放clone
方法&
符号就表示引用:允许你引用某些值而不取得其所有权fn main() {
let mut s1 = String::from("hello");
let len = caculate_length(&mut s1);
println!("The length of '{}' is {}.", s1, len);
}
fn caculate_length(s: &mut String) -> usize {
s.push_str(", world");
s.len()
}
fn main() {
let mut s = String::from("Hello");
{
let s1 = &mut s;
}
let s2 = &mut s;
}
fn first_word(s: &String) -> usize {
let butes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return i;
}
}
s.len()
}
let s = String::from("Hello world");
let hello = &s[0..5];
let world = &s[6..11];
[开始索引..结束索引]
注意:
- 字符串切片的索引范围必须发生在有效的UTF-8字符边界内
- 如果尝试从一个多字节的字符中创建字符串切片,程序会报错并退出
fn first_word(s: &String) -> usize {
let butes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
&s[..]
}
let s = "Hello world!";
fn first_word(s: &String) -> &str {}
fn first_word(s: &str) -> &str {}
struct
关键字,并为整个struct命名struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
let user1 = User {
email: String::from("[email protected]"),
username: String::from("Nikky"),
active: true,
sign_in_count: 556,
};
user1.email = String::from("[email protected]")
;```
>注意:
>- 一旦struct的实例是可变的,那么实例中所有的字段都是可变的
### struct作为函数的返回值
```rust
fn build_user(email: String, username: String) -> User {
User {
username: username,
email: email,
sign_in_count: 1,
active: true,
}
}
fn build_user(email: String, username: String) -> User {
User {
username,
email,
sign_in_count: 1,
active: true,
}
}
let user2 = User {
email: String::from("[email protected]"),
username: String::from("anotherusername"),
active: user1.active,
sign_in_count: user1.sign_in_count,
};
let user2 = User {
email: String::from("[email protected]"),
username: String::from("anotherusername"),
..user1,
};
struct
关键字,后边是名字,以及里面元素的类型struct Color(i32, i32, i32);
struct Point(i32, i32, i32);
let black = Color(0, 0, 0);
let origin = Point(0, 0, 0);
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
struct Rectangle {
width: u32,
length: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.length
}
}
fn main() {
let tect = Rectangle {
width: 30,
length: 50,
}
println!("{}", rect.area())
}
object->something()
和 (*object*).something()
一样p1.distance(&p2);
(&p1).distance(&p2);
String::form()
::
符号
enum IpAddrKind {
V4,
V6,
}
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
::
进行分隔enum IpAddr {
V4(String),
V6(String),
}
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
struct Ipv4Addr {
}
struct Ipv6Addr {
}
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
impl
关键字enum Option<T> {
Some(T),
None,
}
let some_number = Some(5);
let some_string = Some("A String");
let absent_number: Option<i32> = None;
_
通配符:替代其余没列出的值if let Some(3) = v {
println!("three");
}
if let
看作是match的语法糖else
if let Some(3) = v {
println!("three");
} else {
println!("others");
}
mod
关键字mod front_of_house {
mod hosting {
fn add_to_waitlist() {}
fn seat_at_table() {}
}
mod serving {
fn take_order() {}
fn serve_order() {}
fn take_payment() {}
}
}
self
,super
关键字或当前模块的标识符::
// lib.rs
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
pub fn eat_at_restaurant() {
crate::front_of_house::hosting::add_to_waitlist();
front_of_house::hosting::add_to_waitlist();
}
pub
关键字来将某些条目标记为公共的super
:用来访问父级模块路径中的内容,类似文件系统中的..
fn serve_order() {}
mod back_of_house {
fn fix_incorrect_order() {
cook_rider();
super::serve_order();
}
fn serve_order() {}
}
use
关键字将路径导入到作用域内
use crate::front_of_house::hosting;
use fornt_of_house::hosting;
as
关键字可以为引入的路径在本地指定本地的别名use std::fmt::Result;
use std::io::Result as IoRusult;
use
将路径(名称)导入到作用域内后,该名称在此作用域内是私有的pub use
:重导出
use
将特定条目引入作用域
- 标准库(std)也被当作外部包
- 不需要修改Cargo.toml来包含std
- 需要使用
use
将std中的特定条目引入当前作用域
路径相同的部分::{路径差异的部分}
use std::cmp::Ordering;
use std::io;
use std::{cmp::Ordering, io};
use
路径之一是另一个的子路径
self
use std::io;
use std::io::Write;
use std::io::{self, Write};
*
可以把路径中所有的公共条目都引入到作用域use std::collections::*;
;
,而不是代码块:
Vec
,叫做vector
Vec::new()
函数let v: Vec<i32> = Vec::new();
vec!
宏let v = vec![1, 2, 3];
push
方法let mut v = Vec::new();
v.push(1);
get
方法let v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2];
let second = v.get(1);
let v = vec![100, 32, 57];
for i in &v {
println!("{}", i);
}
enum SpreadsheetCell {
Int(i32),
Float(f64),
Text(String),
}
fn main() {
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Float(10.12),
SpreadsheetCell::Text(String::from("blue")),
];
}
str
(或&str
)String::new()
函数to_string()
方法,可用于实现了Display trait的类型,包括字符串字面值String::from()
函数,从字面值创建Stringlet data = "initial contents";
let s = data.to_string();
let s1 = "initial contents".to_string();
let s2 = String::from("initial contents");
push_str()
方法:把一个字符串切片附加到Stringlet mut s = String::from("foo");
s.push_str("bar");
push()
方法:把单个字符附加到Stringlet mut s = String::from("lo");
s.push('l');
+
:连接字符串
fn add(self, s: &str) -> String { ... }
let s1 = String::from("Hello, ");
let s2 = String::from("World!");
let s3 = s1 + &s2;
format!
:连接多个字符串
println!()
类似,但返回字符串lwt s1 = String::from("tic");
lwt s2 = String::from("tac");
lwt s3 = String::from("toe");
let s = format!("{}-{}-{}", s1, s2, s3);
println!("{}", s);
len()
方法[]
和一个范围来创建字符串的切片
let s = &hello[0..4];
chars()
方法bytes()
方法new()
函数insert()
方法use std::collections::HashMap;
fn main() {
let mut scores: HashMap<String, i32> = HashMap::new();
}
use std::collections::HashMap;
fn main() {
let mut scores = HashMap::new();
scores.insert(String::from("Blue"), 10);
}
collect
方法,可以组建一个HashMap:
collect
方法可以把数据整合成很多种集合类型,包括HashMap
use std::collections::HashMap;
fn main() {
let teams = vec![String::from("Blue"), String::from("Yellow")];
let intial_scores = vec![10, 50];
let scores: HashMap<_, _> = teams.zip(intial_scores.iter()).collect();
}
get()
方法
for (k, v) in &scores {
println!("{}: {}", k, v);
}
entry()
方法:检查指定的K是否对应一个V
or_insert()
方法:
let e = scores.entry(String::from("Yellow"));
println!("{:?}", e);
e.or_insert(50);
scores.entry(String::from("Blue")).or_insert(50);
use std::collection::HashMap;
fn main() {
let text = "hello world wonderful world";
let mut map = HashMap::new();
for word in text.split_whitespace() {
let count = map.entry(word).or_insert(0);
+count += 1;
}
println!("{:#?}", map);
}
Result
panic!
宏panic!
宏执行:
panic = 'abort'
RUST_BACKTRACE
可得到回溯信息--release
)enum Result<T, E> {
Ok(T),
Err(E),
}
T
:操作成功的情况下,Ok变体里返回的数据的类型E
:操作失败的情况下,Err变体里返回的错误的类型use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => {
panic!("Error opening file: {:?}", error);
}
};
}
use std::fs::File;
fn main() {
let f = File::open("hello.txt");
let f = match f {
Ok(file) => file,
Err(error) => match error.kind() {
ErrorKind::NotFound => match File::create("hello.txt") {
Ok(fc) => fc,
Err(e) => panic!("Error creating file: {:?}", e);
},
other_error => panic!("Error opening the file: {:?}", other_error),
},
};
}
let f = File::open("hello.txt").unwrap_or_else(|error| {
if error.kind() == ErrorKind::NotFound {
File::create("hello.txt").unwrap_or_else(|error| {
panic!("Error creating file: {:?}", error);
})
} else {
panic!("Error opening file: {:?}", error);
}
});
unwrap()
:match 表达式的一个快捷方法:
panic!
宏expect()
:和unwrap类似,但可以指定错误信息let f = File::open("hello.txt").expect("无法打开文件");
use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Resutl<String, io::Error> {
let f = File::open("hello.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
fn main() {
let result = read_username_form_file();
}
?
运算符:传播错误的一种快捷方式use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Resutl<String, io::Error> {
let f = File::open("hello.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let result = read_username_form_file();
}
return
注意:?运算符只能用于返回Result类型的函数
from()
函数:
?
所应用的错误,会隐式的被from()
函数处理use std::fs::File;
use std::io;
use std::io::Read;
fn read_username_from_file() -> Resutl<String, io::Error> {
let mut s = String::new();
let f = File::open("hello.txt")?.read_to_string(&mut s)?;
Ok(s)
}
fn main() {
let result = read_username_form_file();
}
use std::fs::File;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let f = File::open("hello.txt")?;
Ok(())
}
Box
是 trait 对象:
fn main() {
loop {
let guess = "32";
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
if guess < 1 || guess > 100 {
println!("The secret number will be between 1 and 100.");
continue;
}
}
}
pulic struct Guess {
value: i32;
}
impl Guess {
pub fn new(value: i32) -> Guess {
if value < 1 || value > 100 {
panic!("Guess value must be between 1 and 100, got {}", value);
}
Guess { value }
}
pub fn value(&self) -> i32 {
self.value
}
}
fn main() {
let guess = "32";
let guess: i32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
let guess = Guess::new(guess);
}
fn largest(list: &[T]) -> T { ... }
struct Point<T> {
x: T,
y: T,
}
struct Point<T, U> {
x: T,
y: U,
}
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
impl Point
impl Point
struct Point<T, U> {
x: T,
y: U,
}
impl<T, U> Point<T, U> {
fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
Point {
x: self.x,
y: other.y,
}
}
}
trait
;
结尾pub trait Summary {
fn summarize(&self) -> String;
}
impl Xxxx for Tweet {...}
pub trait Summary {
fn summarize(&self) -> String {
String::from("Read more ...")
}
}
pub trait Summary {
fn summarize_author(&self) -> Stromg;
fn summarize(&self) -> String {
format!("Read more from {} ...", self.summarize_author())
}
}
pub fn notify(item: impl Summary) {
println!("Breaking news! {}", item.summarize());
}
pub fn notify<T: Summary>(item: T) {
println!("Breaking news! {}", item.summarize());
}
+
指定多个 Trait boundpub fn notify(item: impl Summary + Display) {
println!("Breaking news! {}", item.summarize());
}
pub fn notify<T: Summary + Display>(item: T) {
println!("Breaking news! {}", item.summarize());
}
pub fn notify<T: Summary + Display, U: Clone + Debug>(a: T, b: U) -> String {
format!("Breaking news! {}", a.summarize());
}
pub fn notify<T, U>(a: T, b: U) -> String
where T: Summary + Display,
U: Clone + Debug,
{
format!("Breaking news! {}", a.summarize());
}
pub fn notify(s: &str) -> impl Summary { }
fn larget<T: PartialOrd + Copy>(list: &[T]) -> T {}
use std::fmt::Display;
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self {s, y}
}
}
impl <T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x > self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if s.len() > y.len() {
x
} else {
y
}
}
'
开头'a
&
符号后&i32
一个引用&'a i32
带有显式生命周期的引用&'a mut i32
带有显式生命周期的可变引用单个生命周期标注本身没有意义
<>
里fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if s.len() > y.len() {
x
} else {
y
}
}
'a
的实际生命周期是:x和y两个生命周期中较小的那个struct ImportantExcerpt<'a> {
part: &'a str,
}
&self
或 &mut self
(是方法),那么 self 的生命周期会被赋给所有的输出生命周期参数==impl
后声明struct ImportantExcerpt<'a> {
}
impl<'a> ImportantExcerpt<'a> {
}
'static
是一个特殊的生命周期:整个程序的持续时间
'atatic
生命周期
let s: &'static str = "I have a static lifetime.";
'static
生命周期前要三思:
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
where T: Display,
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {}
test
属性(attribute)进行标注
#[test]
,可以把函数变成测试函数cargo test
命令运行所有测试函数
assert!
宏,来自标准库,用来确定某个状态是否为true
panic!
,测试失败==
和!=
运算符assert!
、assert_eq!
、assert_ne!
添加可选的自定义消息
assert!
:第1个参数必填,自定义消息作为第2个参数assert_eq!
和 assert_ne!
:前2个参数时必填的,自定义消息作为第3个参数format!
宏,可以使用 {}
占位符should_panic
属性(attribute):
should_panic
属性添加一个可选的 expected
参数:
#[should_panic(expected = "Guess value must be less than or equal to 100")]
#[should_panic]
cargo test
的行为:添加命令行参数cargo test
的参数:紧跟 cargo test
后--
之后cargo test --help
cargo test -- --help
--test-threads
参数,后边跟着线程的数量cargo test --test-threads=1
cargo test -- --show-output
cargo test
的参数cargo test one_hundred
cargo test add
ignore
属性(attribute)#[test]
#[ignore]
fn it_works() {}
cargo test -- --ignored
#[cfg(test)]
标注:
cargo test
才编译和运行代码cargo build
则不会#[cfg(test)]
标注cargo test
才会编译代码,包括模块中的 helper
函数和 #[test]
标注的函数#[cfg(test)]
,tests 目录被特殊对待
cargo test
,才会编译 tests 目录下的文件cargo test 函数名
cargo test --test 文件名
main.rs
use std::{env, process};
use minigrep::Config;
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::new(&args).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {}", err);
process::exit(1);
});
if let Err(e) = minigrep::run(config) {
eprintln!("Application error: {}", e);
process::exit(1);
};
}
lib.rs
use std::error::Error;
use std::{env, fs};
use std::io::BufRead;
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(config.filename)?;
let results = if config.case_sensitive {
search(&config.query, &contents)
} else {
search_case_insensitive(&config.query, &contents)
};
for line in results {
println!("{}", line);
}
println!("With text:\n{}", contents);
Ok(())
}
pub struct Config {
pub query: String,
pub filename: String,
pub case_sensitive: bool,
}
impl Config {
pub fn new(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("Not enough arguments");
}
let query = args[1].clone();
let filename = args[2].clone();
let case_sensitive = env::var("CASE_INSENSITIVE").is_err();
Ok(Config { query, filename, case_sensitive })
}
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new();
for line in contents.lines() {
if line.contains(query) {
results.push(line);
}
}
results
}
pub fn search_case_insensitive<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new();
let query = query.to_lowercase();
for line in contents.lines() {
if line.to_lowercase().contains(&query) {
results.push(line);
}
}
results
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn case_sensitive() {
let query = "dust";
let contents = "\
Rust:\
safe, fast, productive.\
Pick three.\
Duct tape.";
assert_eq!(vec!["safe, fast, productive."], search(query, contents))
}
#[test]
fn case_insensitive() {
let query = "rUsT";
let contents = "\
Rust:\
safe, fast, productive.\
Pick three.\
Trust me.";
assert_eq!(vec!["Rust:", "Trust me."], search_case_insensitive(query, contents))
}
}
let expensive_clouser = |num: u32| -> u32 {}
注意:闭包的定义最终只会为参数/返回值推断出唯一具体的类型
fn add_one_v1 (x: u32) -> u32 { x + 1 }
fn add_one_v2 = |x: u32| -> u32 { x + 1 };
fn add_one_v3 = |x| { x + 1 };
fn add_one_v4 = |x| x + 1;
Fn
FnMut
FnOnce
FnOnce
FnMut
Fn
FnOnce
FnMut
Fn
move
关键字,可以强制闭包取得它所使用的环境值的所有权
Fn
,基于闭包体里的情况,如果需要FnOnce
或FnMut
,编译器会再告诉你pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// method eith default implementations elided
}
next
next
:
Some
里None
next
方法iter
方法:在不可变引用上创建迭代器into_iter
方法:创建的迭代器会获得所有权iter_mut
方法:迭代可变的引用next
方法
next
方法的原因之一next
的方法叫做“消耗性适配器”
sum
方法(就会耗尽迭代器)
next
,遍历所有元素map
collect
方法:消耗性适配器,把结果收集到一个集合类型中filter
方法:
next
方法struct Counter {
count: u32,
}
impl Counter {
fn new() -> Counter {
Counter {count: 0}
}
}
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Seof::Item> {
if self.count < 5 {
self.count += 1;
Some(self.count)
} else {
None
}
}
}
let buffer: &mut [i32];
let coefficients: [i64; 12];
let qlp_shift: i16;
for i in 12..buffer.len() {
let pridiction = coefficients.iter()
.zip(&buffer[i - 12..i])
.map(|(&c, &s)| c * s as i64)
.sum::<i64>() >> qlp_shift;
let delta = buffer[i];
buffer[i] = prediction as i32 + delta;
}
dev profile
:适用于开发,cargo build
release profile
:适用于发布,cargo build -release
[profile.xxxx]
区域,在里面覆盖默认配置的子集///
cargo doc
cargo doc --open
# Examples
# Panics
:函数可能发生 panic 的场景# Errors
:如果函数返回 Result,描述可能的错误种类,以及可导致错误的条件# Safety
:如果函数处于 unsafe 调用,就应该解释函数 unsafe 的原因,以及调用者确保的使用前提cargo test
:将把文档中的示例代码作为测试来运行//!
pub use
:可以重新导出,创建一个于内部私有结构不同的对外公共结构cargo login [你的API token]
~/.cargo/credentials
cargo publish
命令cargo publish
进行发布cargo yank --vers 1.0.1
cargo yank --vars 1.0.1 --undo
cargo install
cargo install
安装的二进制文件存放在根目录的 bin 文件夹$HOME/.cargo/bin
cargo something
cargo --list
cargo install
来安装扩展,像内置工具一样来运行&
Box
:在 heap 内存上分配值Rc
:启用多重所有权的引用计数类型Ref
和 RefMut
,通过 RefCell
访问:在运行时而不是编译时强制借用规则的类型Box
时最简单的智能指针:
fn main() {
let b = Box::new(5);
println!("b = {}", b);
}
Vec
是更好的选择fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
enum List {
Cons(i32, List),
Nil,
}
enum Message {
Quit,
Move {x: i32, y: i32},
Write(String),
ChangeColor(i32, i32, i32),
}
Box
是一个指针,Rust 知道它需要多少空间,因为:
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
enum List {
Cons(i32, Box<List>),
Nil,
}
Box
:
*
的行为==fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
Box
可以代替上例中的引用fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
Box
被定义成拥有一个元素的 tuple structuse std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type target = T;
fn deref(&delf) -> &T {
&self.0
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
deref
方法:
self
drop
方法
std::mem::drop
函数,来提前 drop 值Rc
Rc
不在预导入模块(prelude)Rc::clone(&a)
函数:增加引用计数Rc::strong_count(&a)
:获得引用计数Rc::weak_count
函数:弱引用计数Rc
只能用于单线程场景Rc::clone()
:增加引用,不会执行数据的深度拷贝操作clone()
:很多会执行数据的深度拷贝操作Rc
通过不可变引用,使你可以在程序不同部分之间共享只读数据Rc
不同,RefCell
类型代表了其持有数据的唯一所有权Box | RefCell |
---|---|
编译阶段强制代码遵守借用规则 | 只会在运行时检查借用规则 |
否则出现错误 | 否则触发panic |
编译阶段 | 运行时 |
---|---|
尽早暴露问题 | 问题暴露延后,甚至到生产环境 |
没有任何运行时开销 | 因借用计数产生些许性能损失 |
对大多数场景时最佳选择 | 实现某些特定的内存安全场景(不可变环境中修改自身数据) |
是Rust的默认行为 |
Rc
相似,只能用于单线程场景Box | Rc | RefCell | |
---|---|---|---|
同一个数据的所有者 | 一个 | 多个 | 一个 |
可变性、借用检查 | 可变、不可变借用(编译时检查) | 不可变借用(编译时检查) | 可变、不可变借用(运行时检查) |
borrow()
方法
borrow_mut()
方法:
Cell
:通过复制类访问数据Mutex
:用于实现跨线程情形下的内部可变性模式thread::spawn
函数可以创建新线程:
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("hi number {} form the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} form the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
}
thread::sleep
会导致当前线程暂停执行thread::spawn
函数的返回值类型时 JoinHandlejoin
方法,可以等待对应的其他线程的完成join
方法:调用 handle 的 join 方法会阻止当前运行线程的执行,直到 handle 所表示的这些线程终结fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} form the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} form the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
thread::spawn
函数一起使用,它允许你使用其他线程的数据fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here is a vector: {:?}", v);
});
handle.join().unwrap();
}
Channel
(标准库提供)mpsc::channel
函数来创建 Channel
fn main() {
let (tx, rx) = mspc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
recv()
方法:阻止当前线程执行,直到 Channel 中有值被送来
try_recv()
方法:不会阻塞
fn main() {
let (tx, rx) = mspc::channel();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::fron_millis(200));
}
});
for received in rx {
println!("Got: {}", received);
}
}
fn main() {
let (tx, rx) = mspc::channel();
let tx1 = mspc::Sender::clone(&tx);
thread::spawn(move || {
let vals = vec![
String::from("1: hi"),
String::from("1: from"),
String::from("1: the"),
String::from("1: thread"),
];
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::fron_millis(200));
}
});
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::fron_millis(200));
}
});
for received in rx {
println!("Got: {}", received);
}
}
Mutex::new(数据)
来创建 Mutex
lock()
方法来获取锁
std::marker::Sync
和 std::marker::Send
这两个traitpub
关键字match VALUE {
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
}
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() {
println!("{}", top);
}
let v = vec!['a', 'b', 'c'];
for (index, value) in v.iter().enumerate() {
println!("{} is at index ().", value, index);
}
let PATTERN = ESPRESSION;
let a = 5;
let (x, y, z) = (1, 2, 3);
fn foo(x: i32) {
}
fn print_coordinates(&(x, y): &(i32, i32)) {
println!("Current location: ({}, {})", x, y);
}
fn main() {
let point = (3, 5);
print_coordinates(&point);
}
let x = 5;
if let Some(x) = a_value
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anthing"),
}
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50."),
Some(y) => println!("Matched, y = {:?}", y),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {:?}", x, y);
|
语法(就是或的意思),可以匹配多种模式let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anthing"),
}
let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("sonething else"),
}
let x = 'c';
match x {
'a'..='j' => println!("early ASCII letter"),
'k'..='z' => println!("late ASCII letter"),
_ => println!("sonething else"),
}
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 }
let Point { x: a, y: b} = p;
assert_eq!(0, a);
assert_eq!(7, b);
let Point { x, y } = p;
assert_eq!(0, x);
assert_eq!(7, y);
match p {
Point { x, y: 0 } => println!("On the x axis at {}", x),
Point { x: 0, y } => println!("On the y axis at {}", y),
Point { x, y } => println!("On neither axis: ({}, {})", x, y),
}
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::ChangeColor(0, 160, 255);
match msg {
Message::Quit => println!("The Quit variant has no data to destructure."),
Message::Move { x, y } => println!("Move in the x direction {} and in the y direction {}", x, y),
Message::Write(text) => println!("Text message: {}", text),
Message::ChangeColor(r, g, b) => println!("Change the color to red {}, green {}, blue {}", r, g, b),
}
}
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => {
println!("Change the color to red {}, green {}, blue {}", r, g, b);
}
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!("Change the color to hue {}, saturation {}, and value {}", h, s, v);
}
_ => (),
}
}
struct Point {
x: i32,
y: i32,
}
fn main() {
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
}
_
_
配合其他模式_
开头的名称..
(忽略值的剩余部分)fn foo(_: i32, y: i32) {
println!("This is only uses the y parameter: {}", y);
}
fn main() {
foo(3, 4);
}
fn main() {
let mut setting_value = Some(5);
let new_setting_value = Some(10);
match (setting_value, new_setting_value) {
(Some(_), Some(_)) => {
println!("Can't overwrite an existing customized value.");
}
_ => {
setting_value = new_setting_value;
}
}
println!("setting is {:?}", setting_value);
}
fn main() {
let _x = 5;
let y = 10;
}
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{:?}", s);
}
struct Point {
x: i32,
y: i32,
z: i32,
}
fn main() {
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
Point { s, .. } => println!("s is {}", x);
}
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, .., last) => {
println!("Some numbers: {}, {}", first, last);
}
}
}
fn main() {
let num = Some(4);
match num {
Some(x) if x < 5 => println!("less than five: {}", x),
Some(x) => println!("{}", x),
None => (),
}
}
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50."),
Some(n) if n == y => println!("Matched, n = {:?}", n),
_ => println!("Default case, x = {:?}", x),
}
println!("at the end: x = {:?}, y = {:?}", x, y);
}
fn main() {
let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("yes"),
_ => println!("no"),
}
}
@
符号让我们可以创建一个变量,该变量可以测试某个值是否与模式匹配的同时保存该值enum Message {
Hello { id: i32 },
}
fn main() {
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: id_variable @ 3..=7,
} => {
println!("Found an id in range: {}", id_variable)
}
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message::Hello { id } => {
println!("Found some other id: {}", id)
}
}
}
unsafe
关键字来切换到unsafe rust,开启一个块,里面放着unsafe代码unsafe
并没有关闭借用检查或停用其他安全检查*mut T
*const T
。意味着指针在解引用后不能直接对其进行赋值*
不是解引用符号,它是类型名的一部分unsafe
关键字
extern
关键字:简化创建和使用外部函数接口(FFI)的过程extern
创建接口,其他语言通过它们可以调用Rust的函数extern
关键字,并指定ABI#[no_mangle]
注解:避免Rust在编译时改变它的名称#[no_mangle]
pub extern "C" fn call_from_c() {
println!("Just called a Rust function form C!");
}
static HELLO_WORLD: &str = "Hello, world!";
fn main() {
println!("name is: {}", HELLO_WORLD);
}
'static
生命周期的引用,无需显式标注unsafe
关键字
泛型 | 关联类型 |
---|---|
每次实现trait时需要标注类型 | 无需标注类型 |
可以为一个类型多次实现某个trait(不同的泛型参数) | 无法为单个类型多次实现某个trait |
std::ops
中列出的那些trait来重载一部分相应的运算符::function(receiver_if_method, next_arg, ...);
type
关键字!
的特殊类型:
let s1:str = "Hello there!";
let s2:str = "how it going?";
&dyn Trait
或 Box(Rc)
之后fn generic<T: ?Sized>(t: &T) {}
#[derive]
宏,用于struct或enum,可以为其指定随 derive 属性添加的代码macro_rules!