Rust概述

Rust是Mozilla公司發起的一個開源項目。它注重安全、性能和併發,是一種系統級編程語言。Rust是針對多核體系提出的語言,而且吸取一些其餘動態語言的重要特性,好比不須要管理內存,好比不會出現Null指針等等。相比C/C++這些底層語言,rust不但具有底層控制力,且具備良好的高級語言特性,生態系統。Rust一經誕生就被運用於servo瀏覽器內核項目開發,具有實戰經歷。php

首先,在學習rust以前要有這樣的預期:rust不是python,不要指望一個星期迅速掌握。
然而,掌握以後比如光劍在手,能夠盡情釋放原力。python

近期學習rust,是由於rust是支持webassembly的第二個語言,且性能強悍。git

安裝 & 升級

安裝:curl https://sh.rustup.rs -sSf | sh
升級:rustup updategithub

簡單類型

rust支持這些整型數值:i32 u32 i8 u8 i16 u16 isize usize
浮點類型:f32 f64
其餘:char, boolweb

變量聲明以下。類型非必須,不少狀況下編譯器能夠判斷。編程

let a = 1;
let a = 1_f32;
let a: f32 = 1.0;

字符串

rust字符串都是合法的utf-8編碼字符。數組

let s = "Rust❤";

組合類型

tuple

元組是臨時的複合數據類型。瀏覽器

// a tuple of type (i32, f32)
let t = (1, 2.0); // 如今有了t.0, t.1

Vector

Vector是動態數組,大小可變。安全

let mut v = Vec::new();
v.push(1);
v.push(2);

let mut v1 = vec![1, 2, 3];

HashMap

use std::collections::HashMap;
let mut score = HashMap::new();
score.insert("Tom", 13);
score.insert("Joe", 16);

其餘

Battery included!
std::collections下還包括:HashSet, BTreeMap, BinaryHeap, LinkedList, VecDeque, BTreeSet等。併發

struct

3種struct類型。

// unit struct
struct Man;
let m = Man;

// tuple struct
struct Man(String, u8);
let m = Man(String::from("Tom"), 12); // m.0, m.1;

// named-field struct
struct Man {
    name: String,
    age: u8
}
let m = Man {
    name: String::from("Tom"),
    age: 12
}; // m.name m.age;

使用impl塊給struct添加實現。

impl Man {
    fn new(name: String, age: u8) -> Man {
        Man {
            name, age
        }
    }
    fn eat(&mut self, food: String) {
        // ...
    }
}
  • new是個構造函數,名字無妨,你叫create也行,不過最好遵照規範。
  • &mut self後面再講,說明eat是個方法。

enum

enum在rust裏獲得了加強,每一個enum值均可以附加其餘數據類型。

Option

rust使用Option enum解決null引用問題。

enum Option<T> {
    None,
    Some(T),
}
struct Man {
    name: String,
    age: u8,
    job: Option<String>
}
let m = Man {
    name: String::from("Tom"),
    age: 30,
    job: Some(String::from("Farmer"))
};

Result

rust使用Result enum做爲異常處理機制,全部可能異常的函數都返回Result

enum Result<T, E> {
    Ok(T),
    Err(E),
}

文件打開函數返回一個Result類型。
File::open<P: AsRef<Path>>(path: P) -> Result<File, std::io::Error>

語法

mut

沒有標記mut的變量,不支持修改。

let a = 1;  // change to: let mut a = 1;
a = 2; // Error: cannot assign twice to immutable variable

表達式

rust是基於表達式的語言,不少常見的語法是表達式。(表達式有返回值)

let n = if true {
    10
} else {
    -1
};

fn add(a: i32, b: i32) -> i32 {
    a + b  // 注意沒有分號,加了分號就沒有返回值了。
}

解構

// destrucure tuple
let (a, b) = (1, 2);

// destrucure tuple struct
let m = Man(String::from("Tom"), 12);
let Man (name, age) = m;

// destrucure named-field struct
let m = Man {
    name: String::from("Tom"),
    age: 12
};
let Man {name, age} = m;

match

match是升級版的switch,還支持解構賦值,條件,變量綁定等。match須要窮舉全部可能。能夠用 _ 匹配剩下的可能。

match File::open("foo.txt") {
    Ok(f) => handle_file(f),
    Err(e) => println!("Something's wrong {}", e),
}

if let

if let語句是條件判斷 + 解構。

if let Ok(f) = File::open("foo.txt") {
    handle_file(f);
}

模塊

mod: 組織模塊結構
use: 在當前模塊引入

單文件mod

mod jim {
    pub mod money {
        pub fn pay() {
            println!("10$ to you!");
        }
    }
}
mod tom {
    pub fn charge() {
        use jim;
        jim::money::pay();
    }
}

fn main() {
    tom::charge();
}

多文件mod

rust-chart
 ├── main.rs
 ├── utils.rs
 └── chart
     ├── mod.rs
     └── kline.rs

main.rs

mod utils;
mod chart;

chart/mod.rs

pub mod kline;

utils.rs

pub fn get_size() -> (u32, u32) {
...
}

chart/kline.rs

use utils;
utils::get_size();

全部權, move & copy

任何一個變量都是屬於一個做用域。做用域結束了,變量就刪除了。
這個做用域就擁有這個變量的全部權。

fn main() {
    {
        let x = 1;
    }
    println!("{}", x); // Error: x is dropped
}

每一個數據類型賦值要麼move要麼copy。
copy type: i32, u32, f32, f64 ...
move type: String, Vec, HashMap

move類型之因此是move,由於複製成本過高。
move表示全部權的轉移。

fn main() {
    let n = 1;
    let n2 = n;
    println!("{} {}", n, n2);
    
    let v = vec![1, 2];
    let v2 = v;
    println!("{}", v[0]); // Error: v is moved
}

借用 & 生命週期

let a = &v1;  // a的類型 &i32
let b = &mut v2; // b的類型 &mut i32

一個變量能夠擁有:

  • 多個不可變引用
  • 只能有一個可變引用, 0個不可變引用
let mut v = 1_i32;
let a = &mut v;
let b = &mut v; // Error: cannot borrow `v` as mutable more than once at a time

如今咱們再試圖理解這段代碼:

impl Man {
    fn new(name: String, age: u8, weight: u8) -> Man {
        Man {
            name, age, weight
        }
    }
    fn eat(&mut self, food: String) {
        self.weight += 10;
        println!("{} eats a {}! Now weight: {}", self.name, food, self.weight);
    }
    fn sleep(&self) {
        println!("{} sleeps!", self.name);
    }
}

&mut self自動獲取實例的可變引用。
&self自動獲取實例的不可變引用。

vector, array, slice

vector大小可變,堆上分配。
array大小不可變。
slice是array或vector的一段引用。

let vector = vec![1, 2, 3, 4, 5];
let array = [2, 3];
let slice = &vector[1..3];

String, &str

&str是對String的借用(引用),是個指向String的胖指針。

let s1 = "abc"; // &'static str
let s2 = String::from("abc"); // String

生命週期

被借用變量生命週期 > 借用者生命週期。

fn main() {
    let v;
    {
        let n = 10_i32;
        v = &n; // Error: `n` does not live long enough
    }
}

編譯器沒法判斷變量的生命週期時,須要標記生命週期。

fn main() {
    let a = 100;
    let c;
    {
        let b = 4;
        c = choose(&a, &b);
    }
    println!("{}", c);
}

fn choose<'a, 'b>(a: &'a i32, b: &'b i32) -> &'a i32 {
    a
}

trait

trait相似於其餘編程語言中的接口。

  • trait使代碼通用
fn calc<T: Into<f64>>(x: T) -> f64 {
    x.into() * 2.
}
calc(10_i32);
calc(10_u32);
calc(10_f32);
  • trait能夠給類型增長實現
pub trait ToString {
    fn to_string(&self) -> String;
}
impl ToString for Man {
    fn to_string(&self) -> String {
        format!("Man {}", self.name)
    }
}
println!("{}", m);

甚至能夠給任意類型添加實現。

trait Barker {
    fn bark(&self);
}

impl<T> Barker for T {
    fn bark(&self) {
        println!("bark bark");
    }
}

fn main() {
    31.bark();
}

Orphan rule: 只要trait或類型有一個在當前包內,纔可添加trait實現。

  • trait object: dynamic dispatch
struct Dog;
struct Cat;

trait Singer {
    fn sing(&self);
}

impl Singer for Dog {
    fn sing(&self) {
        println!("woof");
    }
}

impl Singer for Cat {
    fn sing(&self) {
        println!("mew");
    }
}

fn main() {
    let a: &Singer = &Dog;
    a.sing();
    let a: &Singer = &Cat;
    a.sing();
}

Smart pointer

Box

堆上分配

let b = Box::new(1);

Rc

堆上分配+引用計數

struct Man {
    
}

RefCell & Cell

聲明一個不可變對象,其內部是可變的...
RefCell borrow(), borrow_mut()方法在運行時檢測借用規則,不然panic。

let c = RefCell::new(Man {
    name: "Bill".to_string(),
    age: 32
});
c.borrow_mut().age = 44;

RefCell主要用於引用類型。
Cell主要用於Copy類型。

macro

derive

#[derive(Debug)]
struct Man {
    name: String
}

println

佔位 {}
佔位Debug輸出 {:?}
佔位Debug輸出+beatify {:#?}

let m = Man{
    name: String::from("Joe")
};
println!("{greet}, {:?}", m, greet="Welcome");

format

let s = format!("{greet}, {:?}", m, greet="Welcome");

工具

Cargo

建立新項目

cargo new --bin demo-rust
cargo new --lib demo-rust

Cargo.toml配置文件

[package]
name = "demo-rust"
version = "0.1.0"
authors = ["Amadeus <gliheng@gmail.com>"]

[dependencies]
futures = "0.1.17"
num = "0.1.40"
cargo run
cargo build
cargo test

std
crates.io
docs.rs

使用外部包

extern crate serde;

resources

相關文章
相關標籤/搜索