# rust.rs
fn main() {
println!("Hello, world!");
}
rustc main.rs
./main
cargo new hello_cargo
cargo build
cargo build --release
cargo run
cargo check
cargo-fmt --all
cargo doc --open
use rand::Rng;
use std::cmp::Ordering;
use std::io;
fn main() {
println!("Guess the number!");
let secret_number = rand::thread_rng().gen_range(1, 101);
// println!("The secret number is:{}", secret_number);
loop {
println!("Please input your guess.");
let mut guess = String::new();
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(k) => {
println!("err: {}", k);
continue;
}
};
println!("You guessed: {}", guess);
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("Your win!");
break;
}
}
}
}
67u8 一个u8类型的整数67
98_222 十进制
0xff 十六进制
0o77 八进制
0b1111_0000 二进制
b'A' 字符
let tup:(i32,f64,u8,char) = (500,6.4,1,'宝');
# 索引访问
println!("0:{} 1:{} 2:{} 3:{}",tup.0,tup.1,tup.2,tup.3);
# 解构destructuring
let (a,b,c,d) = tup;
println!("a:{} b:{} c:{} d:{}",a,b,c,d);
let a = [1,2,3,4];
let a : [u8;4]= [1, 2, 3, 4];
println!("0:{} 1:{} 2:{} 3:{}", a[0], a[1], a[2], a[3]);
let a = [3;5]; // 等价于 let a = [3,3,3,3,3];
语句(statement)指那些执行操作但不返回值得指令,而表达式(expression)则是指会进行计算并产生一个值作为结果的指令
·`。 let x = 5;
let y = {
let x = 3;
x + 1 // 不能有分号;
};
println!("x:{} y:{}", x, y); // x:5 y:4
fn another_function(x: i32) -> i32 {
x + 1
}
分支产生的类型必须一致,否则编译错误
:if
and else
have incompatible typesfn main() {
let mut counter = 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 -= 1;
}
println!("LIFEOFF!");
}
fn main() {
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!("LIFEOFF!");
}
所有权规则
:
Rust中的每一个值都有一个对应的变量作为它的所有者
。在同一时间内,值有且仅有一个所有者
。当所有者离开自己的作用域,它持有的值就会被释放掉
。fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("s1:{} s2:{}", s1,s2); // error[E0382]: borrow of moved value: `s1`
}
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1:{} s2:{}", s1,s2); // s:hello s2:hello
}
fn main() {
let s1 = "hello";
let s2 = s1;
println!("s1:{} s2:{}", s1,s2); // s:hello s2:hello
}
fn main() {
let s = String::from("hello"); // 变量s进入作用域
takes_ownership(s); // s的值被移动进了函数
// 所以它从这里开始不再有效
let x = 5; // 变量x进入作用域
makes_copy(x); // 变量x被传递进入函数
println!("{}",x); // 由于i32是Copy的,所以我们依然可以在这之后使用x
} // x 首先离开作用域,随后是s
// 由于s的值已经发生移动,所以没有什么特别的事发生。
fn takes_ownership(some_string:String){ // some_string进入作用域
println!("::{}",some_string);
}// some_string在这里离开作用域,drop函数被自动调用,占用内存随之释放
fn makes_copy(some_integer:i32){ // some_integer进入作用域
println!("{}",some_integer)
}// some_integer在这里离开了作用域,没有什么特别的事情发生.
fn main() {
let s1 = gives_ownership(); // 函数将它的返回值移动至s1中
let (s2, len) = calculate_length(s1);
println!("The length of '{}' is {}!", s2, len);
}
fn gives_ownership() -> String {
// 返回值移动至调用它的函数内
let some_string = String::from("Hello");
some_string //作为返回值移动至调用函数
}
fn calculate_length(s: String) -> (String, usize) {
let length = s.len();
(s, length) // 返回元组
}
fn main() {
let mut s1 = String::from("hello");
let l = change(&mut s1);
println!("str:{} len:{}", s1, l);
}
fn change(s: &mut String) -> usize {
s.push_str(", world");
s.len()
}// s离开作用域,但是由于它不持有自己所指向值的所有权,所以它不会销毁其指向的数据
// 对于特定作用域中的特定数据来说,一次只能声明一个可变引用作为参数
let mut s = String::from("hello");
let r1 = &mut s;
let r2 = &mut s; // 失败
// 我们不能在拥有不可变引用的同时创建可变引用。
let mut s = String::from("hello");
let r1 = & s; // 成功
let r2 = & s; // 成功
let r3 = &mut s; // 失败
它帮助我们在编译时避免数据竞争。
fn main(){
let ref_to_nothing = dangle();
}
fn dangle() -> &String {
let s = String::from("hello"); // s被绑定到新的String上
&s // 将指向s的引用返回给调用者
} // 变量s在这里离开作用域并随之被销毁,它指向的内存也不再有效
&str
。不可变引用let s = String::from("hello world ccc");
println!("{} {} {} {}",&s[..5],&s[6..11],&s[3..],&s[..]);
let s = "Hello, world!";// 变量s的类型其实就是&str:它是一个指向二进制程序特定位置的切片。
fn ff(sli :&[i32])->&[i32]{
&sli[3..]
}
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}
fn main() {
let mut user1 = User { // 一旦实例可变,那么实例中的所有字段都将是可变
email: String::from("[email protected]"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("[email protected]"); // 可修改
let user2 = User {
email: String::from("[email protected]"),
username: String::from("someusername456"),
..user1 // 其他字段和user1相等可以采用此方式初始化
};
let user3 = build_user(
String::from("[email protected]"),
String::from("someusername789"),
);
}
fn build_user(email: String, username: String) -> User {
User {
email, // 同名可以省略
username,
active: true,
sign_in_count: 1,
}
}
struct Color(i32,i32,i32);
struct Point(i32,i32,i32);
let black = Color(0,0,0);
let origin = Point(0,0,0);
println!("Color {} {} {}",black.0,black.1,black.2);
println!("Point {} {} {}",origin.0,origin.1,origin.2);
#[derive(Debug)] //
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let rectl = Rectangle {width: 30,height: 50,};
println!("rectl is {:#?}",rectl); // {:?} 或 {:#?}
}
#[derive(Debug)]
struct Rectangle {width: u32,height: u32,}
fn main() {
let rectl1 = Rectangle {width: 30,height: 50,};
let rectl2 = Rectangle {width: 30,height: 50,};
println!("rectl area is {:#?}", rectl1.area());
println!("can rectl1 hold rectl2? {} ", rectl1.can_hold(&rectl2));
println!("rectl is {:#?}", Rectangle::square(100));
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
// 方法:为结构体实例指定行为
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
// 关联函数:可以将不需要实例的特定功能放置到结构体的命名空间中
fn square(size: u32) -> Rectangle {
Rectangle {width: size,height: size,}
}
}
enum Message {
Quit,
Move { x: i32, y: i32 }, // 包含一个匿名结构体
Write(String), // 包含了一个String
ChangeColor(i32, i32, i32), // 包含了三个i32值
}
enum Option<T>{
Some(T),
None,
}
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
enum Coin {
Penny,
Nickel,
Dime,
Quarter(String),
}
fn value_in_cents(coin: &Coin) -> u32 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => { // 绑定值的模式
println!("state:{}",state);
25
},
}
}
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
fn main() {
let a = Coin::Penny;
println!("{}", value_in_cents(&a));
let a = Coin::Quarter(String::from("Csq"));
println!("{}", value_in_cents(&a));
}
match coin {
Coin::Quarter(state) => println!("state:{}", state),
_ => count += 1,
}
// 等价
if let Coin::Quarter(state) = coin{
println!("state:{}", state)
}else{
count+=1;
}
模块系统
包
通过定义模块来控制作用域及私有性。
Rust中的所有条目(函数、方法、结构体、枚举、模块及常量)默认都是私有的。处于父级模块中的条目无法使用子模块中的私有条目,但子模块中的条目可以使用它所有祖先模块中的条目。
使用pub暴露路径
使用super关键字构造相对路径
use关键字将路径导入作用域
使用as关键字来提供新的名称
使用pub use重导出名称
pub use crate::front_of_house::hosting; // 当其他包引用此包时,可直接使用hosting::xxx
fn main() {
let v: Vec<i32> = Vec::new(); // 创建空动态数组
let v = vec![1, 2, 3]; // 创建包含了值的新动态数组
let mut v = Vec::new();
v.push(5); // 更新动态数组
v.push(6);
v.push(7);
v.push(8);
let mut v = vec![1, 2, 3, 4, 5];
let third: &i32 = &v[2]; // 索引读取
// 我们持有了一个指向动态数组中元素的不可变引用,但却尝试向这个动态数组的结尾处添加元素,该尝试是不会成功的
// v.push(6); // 编译失败
println!("The third element is {}", third);
match v.get(2) { // v.get()返回Option
Some(third) => println!("The third element is {}", third),
None => println!("There is no third element."),
}
let does_not_exist = v.get(100); // 索引越界返回None
// let does_not_exist = &v[100]; // 越界触发panic
let mut v = vec![1, 2, 3, 4, 5];
for i in &mut v{
*i += 50;
}
v.pop();
} // v离开作用域并随之销毁,销毁动态数组时也会销毁其中的元素
enum SpreadsheetCell{
Int(i32),
Float(f64),
Text(String),
}
let row = vec![
SpreadsheetCell::Int(3),
SpreadsheetCell::Text(String::from("blue")),
SpreadsheetCell::Float(10.12),
];
fn main() {
let mut s = String::new();
// 基于字符串字面量创建String的两种方式
let data = "initial contents";
let mut s = data.to_string();
let mut s = String::from("initial contents");
// 更新字符串
let s2 = " junmo ";
s.push_str(s2);
s.push('k');
println!("s:{} \ns2:{}", s, s2); // 拼接之后字符串s2还能使用
// 字符串拼接
let s1 = String::from("111");
let s2 = String::from("222");
let s3 = String::from("333");
let s4 = format!("{}-{}-{}", s1, s2, s3);
println!("{} {} {} {}", s1, s2, s3, s4);
let s5 = s1 + &s2+ &s3; // s1不再能使用,所有权转移
println!(" {} {} {}", s2, s3, s5);
// 字符串索引访问时不允许的
let s = "张君宝";
let a = &s[0..3]; // 字符串切片
// 遍历字符串
for i in s.chars(){
println!("{} ",i);// 张君宝
}
for i in s.bytes(){
println!("{} ",i); // 229 188 160 229 144 155 229 174 157
}
println!("{} {}",s,a);
}
fn main() {
use std::collections::HashMap;
let mut s = HashMap::new();
let s1 = String::from("Blue");
let s2 = String::from("Yellow");
s.insert(s1, 10); // s1从这一刻开始失效
s.insert(s2, 50); // s2从这一刻开始失效
// collect构造hashmap
let terms = vec![String::from("Blue"), String::from("Yellow")];
let initial_scores = vec![10, 50];
// HashMap<_, _>不能省略,
let scores: HashMap<_, _> = terms.iter().zip(initial_scores.iter()).collect();
// 获取hashmap值
let key = String::from("Blue");
let score = s.get(&key);
match score{
Some(sss)=>println!("score is {}",sss),
None=>println!("score is None"),
}
for (k,v) in &scores{
println!("{} {}",k,v);
}
// 在键没有对应值时插入数据
let r = s.entry(String::from("Blue")).or_insert(100);
println!("{}",r);
println!("{:?}",s); // {"Blue": 10, "Yellow": 50}
let r = s.entry(String::from("Black")).or_insert(100);
println!("{}",r);
println!("{:?}",s); // {"Black": 100, "Blue": 10, "Yellow": 50}
// 基于旧值更新值
let r = s.entry(String::from("red")).or_insert(0);
*r += 10
}
struct Point{
x:T,
y:U,
}
impl Point {
fn x(&self) -> &T
}
// Enum定义的泛型
enum Result{
Ok(T),
Err(e),
}
fn some_func(t: t,u: U) -> i32 {...}
fn some_func(t: t,u: U) ->i32
where T: Display + Clone,
U: Clone + Debug
{...}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}
pub struct Guess {
value: u32,
}
impl Guess {
pub fn new(value: u32) -> Guess {
if value < 1 || value > 100 {
panic!("guess value must be greater than or equal to 1,got {}.", value);
}else if value >100{
panic!("guess value must be less than or equal to 100,got {}.", value);
}
Guess { value }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(expected="guess value must be less than or equal to 100")]
fn greater_than_100() {
Guess::new(200);
}
}
// 测试通过时返回Ok(()),在失败时返回一个带有String的Err值。
#[test]
fn it_works() -> Result<(),String>{
if 2+2 == 4{
Ok(())
}else{
Err(String::from("two plus two does not equal four"))
}
}
this_test_will_p
Rust允许测试私有函数
use adder;
mod common;
#[test]
fn it_adds_two(){
common::setup();
assert_eq!(4,adder::it_works())
}
let expensive_result = |num|{
println!("calculating slowly...");
thread::sleep(Duration::from_secs(2));
num
};
会触发类型不匹配的错误。
let csq = |x| x;
let s = csq(String::from("Hello"));
let n = csq(2);
let v1:Vec = vec![1,2,3];
// collect方法会消耗迭代器并将结果值收集到某种集合数据类型中。
v1.iter().map(|x| x+1).collect();
[profile.*]
区域,可以覆盖默认设置的任意子集。String
与Vec
可以被算作智能指针,因为它们拥有一片内存区域并允许用户对其进行操作。它们还拥有元数据(例如容量等),并提供额外的功能和保障。Box
在堆上分配数据#[derive(Debug)]
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let a = Box::new(Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil)))))));
println!("Box: {:?}"
, a);
}
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
T:Deref
时,允许&T转换为&U。T:DerefMut
时,允许&mut T转换为&mut U;T:Deref
时,允许&mut T转换为&URust提供了一个名为Rc的类型来支持多重所有权,它名称中的Rc是Reference counting(引用计数)的缩写
。Rc
类型的实例会在内部维护一个用于记录值引用计数的计数器,从而确认这个值是否仍在使用。如果对一个值的引用计数为零,那么就意味着这个值可以被安全地清理掉,而不会触发引用失效的问题。Rc
只能被用于单线程场景中。
Rc
会增加引用计数。使用Rc
可以使单个值拥有多个所有者,而引用计数机制则保证了这个值会在其拥有的所有者存活时一直有效,并在所有者全部离开作用域时被自动清理。enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(1, Rc::new(Cons(2, Rc::new(Cons(3, Rc::new(Nil)))))));
println!("a counting:{}", Rc::strong_count(&a));
let b = Cons(11, Rc::clone(&a));
println!("a counting:{}", Rc::strong_count(&a));
{
let c = Cons(12, Rc::clone(&a));
println!("a counting:{}", Rc::strong_count(&a));
}
println!("a counting:{}", Rc::strong_count(&a));
}
// a counting:1
// a counting:2
// a counting:3
// a counting:2
RefCell
类型代表了其持有数据的唯一所有权。对于使用RefCell的代码,Rust则只会在运行时检查这些规则,并在出现违反借用规则的情况下触发panic来提前中止程序。RefCell
只能被用于单线程场景中。
Rc
允许一份数据由多个所有者,而Box
和RefCell
都只有一个所有者。Box
允许在编译时检查的可变或不可变借用,Rc
仅允许编译时检查的不可变借用,RefCell
允许允许时检查的可变或不可变借用。RefCell
允许我们在运行时检查可变借用,所以即便RefCell
本身是不可变的,我们仍然能够更改其中存储的值。RefCell
的安全接口,分别返回Ref
和RefMut
这两种智能指针,这两种智能指针都实现了Deref,可以把它们作为一般的引用来对待。RefCell
会记录当前存在多少个活跃的Ref
和RefMut
智能指针。每次调用borrow方法时,RefCell
会将活跃的不可变借用计数加1,并且在任何一个Ref
的值离开作用域被释放时,不可变借用计数将减1。RefCell基于上面的技术来维护和编译器同样的借用检查规则:在任何一个给定的时间里,它只允许你拥有多个不可变借用或一个可变借用。将Rc和RefCell结合使用来实现一个拥有多重所有权的可变数据。Rc允许多个所有者持有同一数据,但只能提供针对数据的不可变访问。如果在Rc内存储了RefCell,那么就可以定义出拥有多个所有者且能够进行修改的值了。
use std::{rc::Rc, cell::RefCell};
use crate::List::{Cons,Nil};
#[derive(Debug)]
enum List{
Cons(Rc<RefCell<i32>>,Rc<List>),
Nil,
}
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value),Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(6)),Rc::clone(&a));
let c = Cons(Rc::new(RefCell::new(10)),Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {:?}",a);
println!("a after = {:?}",b);
println!("a after = {:?}",c);
}
let x = 1;
match x {
1|3 => println!("one or three"),
2 => println!("two"),
5...10 => println!("5-10")
_ => println!("other"),
}
let num = (1,2,3,4,5);
match num{
(first,...,last)=>println("some number:{}, {}",first,last);
}
let num = Some(4);
match num{
Some(x) if x<5 => println!("less than five: {}",x);
Some(x) => println!("{}",x),
None => (),
}
let mut num = 5;
// 可以在安全代码内创建裸指针,但不能在不安全代码块外解引用裸指针。
let r1 = &num as *const i32; // 不可变裸指针
let r2 = &mut num as *mut i32; // 可变裸指针
unsafe {
println!("r1 is : {}", *r1);
println!("r2 is : {}", *r2);
}
unsafe{
// 必须在unsafe块中调用unsafe函数
dangerous();
}
unsafe fn dangerous(){} // 定义unsafe函数
// 引用C标准库代码
// "C"指明了外部函数使用的应用二进制接口ABI:它被用来定义函数在汇编层面的调用方式。
extern "C"{
fn abs(input:i32)->i32;
}
unsafe{
println!("-3 abs :{}",abs(-3));
}
pub trait Iterator{
type Item; // 关联类型
fn next(&mut self) -> Option<Self::Item>
}
trait Add<RP = Self> {
type Output;
fn add(self, param: RP) -> Self::Output;
}
struct Point {
x: i32,
y: i32,
}
// 使用范型默认类型
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
struct Millmeters(u32);
struct Meters(u32);
impl Add<Meters> for Millmeters {
type Output = Millmeters;
fn add(self, other: Meters) -> Millmeters {
Millmeters(self.0 + (other.0 * 1000))
}
}
::function(receiver_if_method, next_arg, ...)
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper{
fn fmt(&self,f: &mut fmt::Formatter)->fmt::Result{
write!(f,"[{}]",self.0.join(", "))
}
}
fn return_closure() -> Box<dyn Fn(i32)>{
Box::new(|x| x+1)
}