const A_CONSTANT_VALUE: i32 = 6; let tmp: i32 = 5; // "tmp" attempt to use a non-constant value in a constant const YET_ANTHOER_CONSTANT_VALUE: i32 = A_CONSTANT_VALUE * tmp;
let x = 5; let x = 6; // 允许的语法,x为6
// u32不加的话,会报出compile error, 因为rust无法推断guess的类型 let guess: u32 = "42".parse().expect("Not a number!");
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 |
fn main1() { let tup = (500, 6.4, 1); let (x, y, z) = tup; println!("The value of y is: {y}"); } fn main2() { let x: (i32, f64, u8) = (500, 6.4, 1); let five_hundred = x.0; let six_point_four = x.1; let one = x.2; }
let a: [i32; 5] = [1, 2, 3, 4, 5];x + 1和x + 1;的区别,一个是expression, 一个是statement。fn main() { // {..}代表一个block let y = { let x = 3; x + 1 // 没有分号,代表一个expression,即当前block返回4,同时赋值给y }; println!("The value of y is: {y}"); }
fn five() -> i32 { // 使用->定义返回类型。 5 }
fn main() { let number = 6; if number % 4 == 0 { println!("number is divisible by 4"); } else if number % 3 == 0 { println!("number is divisible by 3"); } else if number % 2 == 0 { println!("number is divisible by 2"); } else { println!("number is not divisible by 4, 3, or 2"); } // 可以直接赋值 let number = if true { 5 } else { 6 }; println!("The number is {}", number); // infinite loop // loop { // println!("again"); // } // 使用loop + break直接使用循环对一个变量赋值 let mut counter = 0; let result = loop { counter += 1; if counter == 10 { break counter * 2; } }; println!("Result is {result}"); // while loop let mut count: i32 = 5; while count != 1 { println!("in while loop"); count -= 1; } // for loop an array let a = [10, 20, 30, 40, 50]; for element in a { println!("the value is: {element}"); } }


s2 = s1 后,s1的owner会转移到s2,也就是说执行完成后s2为这块内存的owner,s1直接被gc。所以在这行代码执行完成后s1不再存在。但是可以clone(类似deep clone)来复制这片内存空间let s1 = String::from("hello"); // s1已经move到了s2, s1在后续scope中不再存在 // let s2 = s1; // 可以使用clone来进行shallowcopy let s2 = s1.clone(); println!("{}, world!", s1);
Copy的Trait到对应类型中,带有Copy Trait的类型可以保证值在assign后继续时候(被copy)。相对应的,在内存中的数据类型(例如String)会带有一个叫做Drop的Trait,实现Drop的Trait不能实现Copy。Copy trait的类型一共5种:即4个初始类型(scalar types)还有仅含有初始类型的tuple,例如(i32, i32) ,而(i32, String)则不是,因为String不是初始类型fn main() { let s1 = String::from("hello"); let (s2, len) = calculate_length(s1); // 由于s1的ownership转换,s1不再是s2,s1无法被重用 println!("The length of '{}' is {}.", s2, len); } fn calculate_length(s: String) -> (String, usize) { let length = s.len(); // len() returns the length of a String (s, length) }
& 符号代表着取对应指针的引用。fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); println!("The length of '{}' is {}. The Ref is {}", s1, len, &s1); } fn calculate_length(s: &String) -> usize { s.len() }
s1 s的关系可以用下图说明, 即s就是一个新的指针指向s1
&s1在传入函数后,可以继续使用的原因是&s1是s1的一个引用,但是因为他不是对应值的owner,所以不会drop。且函数不需要返回来交出ownership,因为引用压根不存在ownership一说。&mut 来创建一个可修改的引用。fn main() { let mut s = String::from("hello"); change(&mut s); // The changed s is hello world println!("The changed s is {s}"); } fn change(some_string: &mut String) { some_string.push_str(", world"); }
fn main() { let mut s = String::from("hello"); change(&mut s); println!("The changed s is {s}"); { let r1 = &mut s; r1.push_str(" inner") } // r1 goes out of scope here, so we can make a new reference with no problems. let r2 = &mut s; r2.push_str(" outter"); // after two &mut, s is $hello, world inner outter println!("after two &mut, s is ${s}") } fn change(some_string: &mut String) { some_string.push_str(", world"); }
let mut s = String::from("hello"); let r1 = &s; // no problem let r2 = &s; // no problem let r3 = &mut s; // BIG PROBLEM println!("{}, {}, and {}", r1, r2, r3);
let mut s = String::from("hello"); let r1 = &s; // no problem let r2 = &s; // no problem println!("{}, {}", r1, r2); let r3 = &mut s; r3.push_str(" world"); // r1, r2的scope在这结束,而在这中间,r3这个mut reference的scope相互重叠了。 println!("{}, {}, {}", r1, r2, r3); // println!("{}", r3); // 使用这行将解决这个问题
fn main() { let reference_to_nothing = dangle(); } fn dangle() -> &String { let s = String::from("hello"); // s is dropped after dangle fn(), but we try to return a reference value to it. &s }
mut.. 符号,merge的顺序与js相反。且..的merge必须放在最后一行。struct User { active: bool, username: String, email: String, sign_in_count: u64, } fn build_user(email: String, username: String) -> User { User { active: true, username: username, email: email, sign_in_count: 1, } } fn main() { let mut user1 = User { active: true, username: String::from("someusername123"), email: String::from("[email protected]"), sign_in_count: 1, }; // user1需要整体标注为mut user1.email = String::from("[email protected]"); let user2 = build_user( String::from("[email protected]"), String::from("hophop") ); // 取user1的username,剩下的采用user2,而非使用user2进行全量覆盖 let merged_user = User {username: user1.username, sign_in_count: user2.sign_in_count, ..user2 }; println!("user email is {}", user1.email); // user1.username已经被merged_user借用,无法再次使用。 // println!("user email is {}", user1.username); // 而sign_in_count的类型属于u64, 属于scalar type, 可以再次使用(实现了Copy Trait) println!("user2 sign_in_count is {}", user2.sign_in_count); println!("merged user name is {}", merged_user.username); // someusername123 println!("merged user email is {}", merged_user.email); // [email protected] }
Rectangle::print()来调用。apply#[derive(Debug)] struct Rectangle { width: u32, height: u32 } impl Rectangle { fn area(&self) -> u32 { self.width * self.height } // method fn print(&self) { println!("The area of the rectangle {:#?} is {}", self, self.area()); } // associated functions fn square(size: u32) -> Self { Self { width: size, height: size, } } } fn main() { let rectangle = Rectangle { width: 40, height: 40 }; // println!("The area of the rectangle {:#?} is {}", rectangle, calc_area(&rectangle)); // println!("The area of the rectangle {:#?} is {}", rectangle, rectangle.area()); rectangle.print(); // 可以使用这种方式(associated functions)调用。 Rectangle::print(&rectangle); // associated functions的调用方式 let square = Rectangle::square(12); square.print(); } fn calc_area (rectangle: &Rectangle) -> u32{ return rectangle.width * rectangle.height; }
enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }
Message枚举拥有4种值,且每种值可以hold不同类型的数据。Option ,Option枚举拥有2个值,None和Some,None代表不存在,Some代表值存在。None和Some可直接在代码中引用。或使用通用的枚举synxtax,例如Option::None the concept that null is trying to express is still a useful one: a null is a value that is currently invalid or absent for some reason.
let x: i8 = 5; let y: Option<i8> = Some(5); let sum = x + y;
y可能为null时,使用Some来代表y这个值能不存在,当y被引用时,一个i8是无法与一个Option<i8>类型相加的,所以需要一定的方式将Some<T>转换为T,进而进行使用。enum Coin { Penny, Nickel, Dime, Quarter, } fn value_in_cents(coin: Coin) -> u8 { match coin { Coin::Penny => 1, Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter => 25, } }
other关键字或者_关键字进行额外分支的处理。enum Coin { Penny, Nickel, Dime, Quarter(UsState), } fn value_in_cents(coin: Coin) -> u8 { match coin { Coin::Penny => 1, // Coin::Nickel => 5, // Coin::Dime => 10, Coin::Quarter(state) => { println!("the state is from {:?}", state); return 25; } // 使用other做缺省处理,例如js中switch case的default other => { println!("other"); return 2; } } } fn main() { println!("value is {}", value_in_cents(Coin::Nickel)); }
_符号指不需要对额外分支做处理。if let简化pattern matching的冗余代码let config_max = Some(3); match config_max { Some(max) => println!("The maximum is configured to be {}", max), _ => (), }
config_max是一个为3的Some,当Some通过match检测后,打印出max的值,否则不做任何事情。在这种case下_的分支就会冗余。if let 可以简化以上代码为:let config_max = Some(3u8); if let Some(max) = config_max { println!("The maximum is configured to be {}", max); }
=左侧的为需要match的条件,=右侧为被match的变量,对应的大括号内的为首个映射上的分支处理代码。unwrap_orunwrap()Option or Result type, assuming that it contains a value. If the Option or Result is Some(value) or Ok(value), unwrap() returns the inner value. However, if the Option or Result is None or Err, unwrap() will panic and crash the program.unwrap_errResult types. It is the counterpart of unwrap() for handling Err variants. If the Result is Ok(value), unwrap_err() will panic and crash the program. But if the Result is Err(error), it returns the inner error value.fn divide(a: i32, b: i32) -> Result<i32, String> { if b == 0 { Err(String::from("Cannot divide by zero")) } else { Ok(a / b) } } fn main() { let result = divide(10, 0); let err_message = result.unwrap_err(); println!("Error occurred: {}", err_message); }
unwrap_or(default)Option or Result, or provide a default value if it is None or Err. If the Option or Result is Some(value) or Ok(value), unwrap_or() returns the inner value. But if the Option or Result is None or Err, it returns the provided default value.unwrap_or_default()unwrap_or(), but it returns the default value of the inner type if the Option or Result is None or Err. The default value is determined by the Default trait implemented for the inner type.unwrap_or_else(default_fn)Option or Result, or provide a fallback value or mechanism if it is None or Err. If the Option or Result is Some(value) or Ok(value), unwrap_or_else() returns the inner value. But if the Option or Result is None or Err, it calls the provided default_fn closure or function to generate the fallback value.fn divide(a: i32, b: i32) -> Result<i32, String> { if b == 0 { Err(String::from("Cannot divide by zero")) } else { Ok(a / b) } } fn main() { let result = divide(10, 2); let value = result.unwrap_or_else(|err| { println!("Error occurred: {}", err); 0 }); println!("Result: {}", value); }
// 从0创建 let mut v: Vec<i32> = Vec::new(); // mutating vector v.push(1); v.push(2); v.push(3); v.push(4); // 包含初始值 let v = vec![1, 2, 3, 4, 5];
push, pop等, 不过多赘述fn iterate_vec(v: &Vec<i32>) { for i in v { println!("the value at index {i} is {}", i); } } fn reading_vec_by_index(v: &Vec<i32>, index: usize) { println!( "reading index {} from vector {:?}, value is {}", index, v, v[index] ); } fn reading_vec_by_get(v: &Vec<i32>, index: usize) { // let third3 = v.get(index); // let result: i32; // match third3 { // Some(v) => result = *v, // None => println!("There is no third element."), // } // return result; // 使用.get去获取值,将会返回一个Option let third4 = v.get(index); if let Some(third) = third4 { println!( "reading index {} from vector {:?}, value is {}", index, v, third ); } else { println!("There is no third element."); } }
fn main() { println!("Hello, world!"); let str = create_str_from_new(); print_str(&str); let str = create_str_with_initial_values(); print_str(&str); let mut str = create_str_from_string_literal(); print_str(&str); str.push_str(" world"); // can push str str.push('!'); // can only push char print_str(&str); // use + operator to append let str_part_1 = String::from("hello"); let str_part_2 = String::from("world"); // 需要使用&进行引用的原因是因为 + operator本质是调用add function,add fn的定义要求传入&str // add fn: fn add(self, s: &str) -> String { // 因为str_part_1的ownership被add拿走,str_part_1在+号后不再存在,而str_part_2为引用,后续依旧可用。 let str = str_part_1 + " " + &str_part_2 + "!"; // print_str(&str_part_1); // 报错 ownership // print_str(&str_part_2); // OK print_str(&str); let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let str = s1 + "-" + &s2 + "-" + &s3; print_str(&str); let s1 = String::from("tic"); let s2 = String::from("tac"); let s3 = String::from("toe"); let str = format!("{s1}-{s2}-{s3}"); print_str(&str); // string不支持index访问。 // 原因是String的本质实现是存放着asciicode的vector: Vec<u8>, // 若允许indexing,则会返回相对应的number,为了保证意外的情况,Rust完全禁止了String indexing // let s1 = String::from("hello"); // let h = s1[0]; // Compile Error } fn create_str_from_new() -> String { let mut s = String::new(); s.push('h'); s.push('e'); s.push('l'); s.push('l'); s.push('o'); s } fn create_str_with_initial_values() -> String { let s = String::from("hello"); s } fn create_str_from_string_literal() -> String { let s = "hello"; s.to_string() } fn print_str(str: &str) { println!("The str created is {}", str); }
Vec<u8> 实现,通过index访问将会返回对应的ascii codeनमस्ते,从bytes角度看,展示为[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164,
224, 165, 135],若能够通过index访问,将会返回number,且无法明确对应的index值。O(1) 复杂度,但实际并不是如此,且无法保证let str = "Здравствуйте"; let s = &str[0..4]; // Зд本身占用4个bytes,0-4会得到Зд,而不是Здра print_str(&s);
Vec<u8> 这个设计的问题。。能不用别用了。。for c in "Зд".chars() { println!("{c}"); }
use std::collections::HashMap; fn main() { let scores = create_hash_map(); let score = scores.get("Blue").copied().unwrap_or(0); println!("score is {}", score); iterate_hash_map(&scores); let field_name = String::from("Favorite color"); let field_value = String::from("Blue"); let mut map = HashMap::new(); map.insert(field_name, field_value); // map.insert(&field_name, &field_value); // ownership已经被转移到了map,后续无法再获取field_name和field_value // println!("field_name {}", field_name); // println!("field_value {}", field_value); update_hash_map(); } fn create_hash_map() -> HashMap<String, i32> { let mut scores = HashMap::new(); scores.insert(String::from("Blue"), 10); scores.insert(String::from("Yellow"), 50); scores } fn iterate_hash_map(map: &HashMap<String, i32>) { for (key, value) in map { println!("{key}: {value}"); } } fn update_hash_map() { let mut scores = HashMap::new(); // overwriting scores.insert(String::from("Blue"), 10); scores.insert(String::from("Blue"), 25); // overwriting by checking if already has value scores.entry(String::from("Yellow")).or_insert(50); scores.entry(String::from("Blue")).or_insert(50); println!("{:?}", scores); }
Cargo.toml 文件进行描述如何构建内含的cratescargo new创建packagesrc/main.rs 是Rust package中默认的crate root:: 调用模块子方法(或枚举或struct),使用pub 进行模块公开,默认模块及模块方法全私有。self调用自身模块的方法,super调用父模块的方法。as进行别名use std::fmt::Result; use std::io::Result as IoResult; fn function1() -> Result { // --snip-- } fn function2() -> IoResult<()> { // --snip-- }
// (1) pub use terminal::Terminal; fn main() { // xxx }
// (2) // 可以直接使用crate的Terminal,其实应该写成 use crate::terminal::Terminal // 但是因为main.rs内部使用了pub use terminal::Terminal, // 相当于将terminal下的Terminal暴露至了crate级别 // 类似js中index.js全部re-export,所有子模块就可以直接从入口处统一导入 use crate::Terminal;
pub struct Size { pub width: u16, pub height: u16, } pub struct Terminal { size: Size, } impl Terminal { pub fn default() -> Result<Self, std::io::Error> { // xxx } pub fn get_size(&self) -> &Size { &self.size } }
panic! 应对不可恢复类型异常fn main() { // a manual panic! call // panic!("plz panic!"); let vec = [1, 2, 3]; // this will break the program vec[99]; }
[profile.release] panic = 'abort'
Result来应对可恢复类型异常fn try_open_file_with_specific_errors() { let greeting_file_result = File::open("hello.txt"); let greeting_file = match greeting_file_result { Ok(file) => file, Err(error) => match error.kind() { // 如果是NotFound的Kind,直接生成文件。 ErrorKind::NotFound => match File::create("hello.txt") { Ok(fc) => fc, Err(e) => panic!("Problem creating the file: {:?}", e), }, other_error => { panic!("Problem opening the file: {:?}", other_error); } }, }; println!("success!, {:#?}", greeting_file) }
Result相关的方法可以简化代码,例如使用unwrap以及expectuse std::fs::File; fn main() { let greeting_file = File::open("hello.txt").unwrap(); let greeting_file = File::open("hello.txt") .expect("hello.txt should be included in this project"); }
Result结果是Ok,unwrap则会直接返回Result内的值,否则会调用panic!。使用expect可以填入自定义的panic信息,报错信息会更加语义化。推荐使用expectErr传递。use std::fs::File; use std::io::{self, Read}; fn read_username_from_file() -> Result<String, io::Error> { let username_file_result = File::open("hello.txt"); let mut username_file = match username_file_result { Ok(file) => file, Err(e) => return Err(e), }; let mut username = String::new(); match username_file.read_to_string(&mut username) { Ok(_) => Ok(username), Err(e) => Err(e), } }
Err分支内直接将错误返回,注意函数返回类型。Result以及matchuse std::fs::File; use std::io::{self, Read}; fn read_username_from_file() -> Result<String, io::Error> { let mut username_file = File::open("hello.txt")?; let mut username = String::new(); username_file.read_to_string(&mut username)?; Ok(username) }
Result后标明? 代表若有错误,直接返回一个Err的Result至外部。Result后带有?则表示会对外界传递Err ,返回类型一定要注意写。trait Summary { fn summarize(&self) -> String; }
pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, } impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location) } } pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool, } impl Summary for Tweet { fn summarize(&self) -> String { format!("{}: {}", self.username, self.content) } }
pub trait Summary { fn summarize(&self) -> String { String::from("(Read more...)") } }
fn need_to_impl_summary<T: Summary>(item: &T) { item.summarize() } // 缩略版 fn need_to_impl_summary_simple(item: &impl Summary) { item.summarize() }
pub fn notify<T: Summary + Display>(item: &T) {} pub fn notify(item: &(impl Summary + Display)) {}
where 关键字fn some_function<T, U>(t: &T, u: &U) -> i32 where T: Display + Clone, U: Clone + Debug, {}
fn returns_summarizable() -> impl Summary { Tweet { username: String::from("horse_ebooks"), content: String::from( "of course, as you probably already know, people", ), reply: false, retweet: false, } }
Summary接口,这里有一个隐形的限制就是返回类型必须得是一种。必能返回2种不同的struct,但是都实现了SumaryLifetimes are another kind of generic that we’ve already been using. Rather than ensuring that a type has the behavior we want, lifetimes ensure that references are valid as long as we need them to be.
fn main() { let r; { let x = 5; r = &x; } println!("r: {}", r); }
r被赋值一个无效的指针x。$ cargo run Compiling chapter10 v0.1.0 (file:///projects/chapter10) error[E0597]: `x` does not live long enough --> src/main.rs:6:13 | 6 | r = &x; | ^^ borrowed value does not live long enough 7 | } | - `x` dropped here while still borrowed 8 | 9 | println!("r: {}", r); | - borrow later used here For more information about this error, try `rustc --explain E0597`. error: could not compile `chapter10` due to previous error
fn main() { let r; // ---------+-- 'a // | { // | let x = 5; // -+-- 'b | r = &x; // | | } // -+ | // | println!("r: {}", r); // | } // ---------+
r的引用存活范围在’a,x的引用存活范围在’b’a是远大于’b的,也就是说x的存活时间没有活到’a结束。这就是borrow checker的原理。fn main() { let x = 5; // ----------+-- 'b // | let r = &x; // --+-- 'a | // | | println!("r: {}", r); // | | // --+ | } // ----------+
x变量可以跟随r一直到末尾。也就满足x的存活时间活到了r结束。borrow checker检查通过。fn longest(x: &str, y: &str) -> &str { if x.len() > y.len() { x } else { y } }
&i32 // a reference &'a i32 // a reference with an explicit lifetime &'a mut i32 // a mutable reference with an explicit lifetime
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
x和y 一致,即只要x y存在,返回值就存在。struct ImportantExcerpt<'a> { part: &'a str, } fn main() { let novel = String::from("Call me Ishmael. Some years ago..."); let first_sentence = novel.split('.').next().expect("Could not find a '.'"); let i = ImportantExcerpt { part: first_sentence, }; }
fn first_word(s: &str) -> &str 将变成 fn first_word<'a>(s: &'a str) -> &strfn first_word<'a>(s: &'a str) -> &str 将变成fn first_word<'a>(s: &'a str) -> &'a strlet s: &'static str = "I have a static lifetime.";
let example_closure = |x| x; let s = example_closure(String::from("hello")); // 报错,Rustc会根据第一次调用进行类型推断,第二次的类型与第一次不同 let n = example_closure(5);
let list = vec![1, 2, 3]; println!("Before defining closure: {:?}", list); // 使用闭包就不报错 let only_borrows = || println!("From closure: {:?}", list); fn only_borrows() { // list报错,can't capture dynamic environment in a fn item println!("From function: {:?}", list); } println!("Before calling closure: {:?}", list); only_borrows(); println!("After calling closure: {:?}", list);
metaprogramming。println! which could take any number of arguments, depending on the format string.macro_rules! 关键字定义,可以在代码中匹配和转换模式。而函数使用 fn 关键字定义,并遵循 Rust 函数的语法规则。metaprogramming)println! 宏就是一个常见的宏。在编写代码时,你可以使用 println!("Hello, {}!", name) 来打印带有变量 name 值的消息。在宏展开时,println! 宏会根据提供的参数生成对应的代码,以在运行时打印消息。这样,你可以在编写代码时使用宏来简化打印操作,而不必手动编写打印代码的重复代码。Parallel要求有多个可处理的CPU核心,而Concurrent要求多线程。如果没有多核CPU来承载多个任务执行,就不能以Parallel来解决问题。
thread::spawn 返回一个JoinHandle, 可以等待当前线程结束或do something elseuse std::thread; use std::time::Duration; fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); for i in 1..5 { println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } // join会等待线程的结束,会成功打印1-9,若没有则会答应出1-4(因为主线程提前退出) handle.join().unwrap(); }
use std::thread; use std::time::Duration; fn main() { let handle = thread::spawn(|| { for i in 1..10 { println!("hi number {} from the spawned thread!", i); thread::sleep(Duration::from_millis(1)); } }); // 若放在中间,join会等待新thread完全运行完成再执行主线程代码 handle.join().unwrap(); for i in 1..5 { println!("hi number {} from the main thread!", i); thread::sleep(Duration::from_millis(1)); } }

cargo package 检查打包后的crate文件cargo publishcargo.toml区分release与dev的profile设置[profile.*]语法区分环境,例如[profile.dev] opt-level = 0 [profile.release] opt-level = 3
///来表示注释为Rust Doc。例如://! # My Crate //! //! `my_crate` is a collection of utilities to make performing certain //! calculations more convenient. /// Adds one to the number given. /// /// # Examples /// /// ``` /// let arg = 5; /// let answer = my_crate::add_one(arg); /// /// assert_eq!(6, answer); /// ``` pub fn add_one(x: i32) -> i32 { x + 1 }
cargo doc生成doc,使用cargo doc —open打开文档预览。assert_eq!会作为一个独立的测试用例在使用cargo test时被调用检测//! 表示当前包的信息,会显示在文档最上方。cargo login: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#setting-up-a-cratesio-accountcargo login xxxxxxxxxxyourapitokenxxxx --registry crates-io—registry crates-io 的命令行设置,可以通过建立.cargo/config.toml 并声明默认发布registry,例如:# .cargo/config.toml [registry] default = "crates-io"
cargo clippy -- -W clippy::pedantic针对所有lint rules的一次校验cargo clean清理build文件,让lint作用于所有文件let results = if config.ignore_case { search_case_insensitive(&config.query, &contents) } else { search(&config.query, &contents) };
let results = match config.ignore_case { true => search_case_insensitive(&config.query, &contents), false => search(&config.query, &contents), };
println!( "The spawned thread is {}", if let true = handler.is_finished() { "finished" } else { "not finished" } );
saturating_addlet width = 5; let sliced = &String::from("xxxxxxxx")[..width]
macro_rules! print_env { ($name: expr) => { println!("{}={}", $name, env!($name)) }; } print_env!("CARGO_PKG_VERSION_MAJOR"); print_env!("CARGO_MANIFEST_DIR"); print_env!("CARGO_PKG_AUTHORS"); print_env!("CARGO_PKG_DESCRIPTION"); print_env!("CARGO_PKG_HOMEPAGE"); print_env!("CARGO_PKG_NAME"); print_env!("CARGO_PKG_REPOSITORY"); print_env!("CARGO_PKG_VERSION"); print_env!("CARGO_PKG_VERSION_MAJOR"); print_env!("CARGO_PKG_VERSION_MINOR"); print_env!("CARGO_PKG_VERSION_PATCH"); print_env!("CARGO_PKG_VERSION_PRE");
cargo new创建新的cargo,cargo run运行cargocrago doc —-open会打开当前crate内相关引用crate的文档Cargo.toml并声明workspaces-members 参考:https://github.com/citrus327/give-rust-one-more-chance/blob/main/Cargo.tomlcargo run,或者在project root使用cargo run --bin [cargo-name]来执行turbofish语法 (涡轮鱼)::<> 就是turbofish。常用于不给变量进行类型定义,而是使用 turbofish 在构造器上直接标注类型let b = Vec::<bool>::new(); // 使用turbofish语法直接表明b的类型 let b: Vec<bool> = Vec::new(); // explicit表明类型