RUST有毒,如何從零開始到接入微服務(wù)集群 第一章

前言

RUST:

  • 適合編程初學(xué)者學(xué)習(xí)、當前適合當團隊的語言選型對象、優(yōu)雅
  • 適合學(xué)習(xí)、適合準備、適合強迫癥、適合
缺點
  • 1 上手困難,相對其他語言有較復(fù)雜的語法和理念,門檻比較高
  • 2 有很多獨有表達式,可讀性較差
  • 3 嚴格的語法限制,如作用域、生命周期等,學(xué)習(xí)成本高
  • 4 目前版本不統(tǒng)一,stable和nightly版本區(qū)別較大
  • 5 不好做語言遷移,生態(tài)還不完全
優(yōu)點
  • 1 有毒,容易上癮
  • 2 社區(qū)開發(fā)速度快,現(xiàn)在是個學(xué)習(xí)的好時候,目前,保持著每 6 周更新一次的節(jié)奏。Rust 發(fā)布的工具鏈包括了 stable、betanightly 三種不同版本。 nightly 是最激進的版本,包含了大量(可能不穩(wěn)定)的新/高級特性。stable 版本目前可能還不支持一些高級特性。beta 介于兩者之間。
  • 3 從語言層面就減少各種開銷和數(shù)據(jù)競爭,更加安全
  • 4 性能

參考資料

官方中文網(wǎng)站
crates 庫類搜索
簡體中文文檔
語法基礎(chǔ)教程
RUST 特性分析 by austenliao
Rust中文社區(qū)
tokio文檔
Rocket文檔

必看語法

借用和引用
匹配
模式
生命周期
更多...

目錄

  • 安裝RUST
  • hello world
  • 使用第三方庫
  • 測試socket stream
  • 搭建http服務(wù)
  • 數(shù)據(jù)庫操作
  • 與golang的壓測對比
  • 接入基于consul的grpc微服務(wù)集群

一 安裝RUST

  • 下載
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • 激活環(huán)境
source $HOME/.cargo/env
  • 檢查是否安裝成功
$ cargo --version
cargo 1.38.0 (23ef9a4ef 2019-08-20)

cargo 命令介紹

  • cargo build 可以構(gòu)建項目
  • cargo run 可以運行項目
  • cargo test 可以測試項目
  • cargo doc 可以為項目構(gòu)建文檔
  • cargo publish 可以將庫發(fā)布到 crates.io。

二 helloworld

$ cargo new myhello
  • 生成的文件結(jié)構(gòu)
$ tree
.
├── Cargo.toml
└── src
    └── main.rs
//main.rs
fn main() {
    println!("Hello, world!");
}

//Cargo.toml
[package]
name = "myhello"
version = "0.1.0"
authors = ["root"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
  • 運行
$ cargo run
Compiling myhello v0.1.0 (/mnt/hgfs/winwork/rust/myhello)
error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

error: aborting due to previous error

error: Could not compile `myhello`.

To learn more, run the command again with --verbose.
  • 失敗了,新裝的虛擬機環(huán)境不夠完全,注意最好換成aliyun的源再繼續(xù)
$ sudo apt install build-essential
  • 再次運行,成功
$ cargo run
   Compiling myhello v0.1.0 (/mnt/hgfs/winwork/rust/myhello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.54s
     Running `target/debug/myhello`
Hello, world!

三 簡單使用第三方庫

  • 參照官方示例,使用ferris-says庫,用來畫個say hi的小人
// main.rs
use ferris_says::say; // from the previous step
use std::io::{stdout, BufWriter};

fn main() {
    let stdout = stdout();
    let out = b"Hello fellow Rustaceans!";
    let width = 24;
    let mut writer = BufWriter::new(stdout.lock());
    say(out, width, &mut writer).unwrap();
}
# Cargo.toml中加入
[dependencies]
ferris-says = "0.1"
# 編譯 后可在target目錄中找到可執(zhí)行文件
$ cargo build
# 或者直接運行
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 1.79s
     Running `target/debug/myhello`
----------------------------
| Hello fellow Rustaceans! |
----------------------------
              \
               \
                  _~^~^~_
              \) /  o o  \ (/
                '_   -   _'
                / '-----' \

四 測試socket stream

  • 當我們需要寫功能的時候,可以從crates.io 可以搜索需要用到的庫
image.png

注意:
Documentation 會指向官方文檔網(wǎng)站
Repository 會指向github

  • tokio 異步編程框架是使用人數(shù)較多的框架,不僅是引用量和下載量都是最高的,而且是官方支持的項目。但是rust生態(tài)目前還不是很完善,因此很多項目都不穩(wěn)定,從github中可以看到

NOTE: Tokio's master is currently undergoing heavy development. This branch and the alpha releases will see API breaking changes and there are currently significant performance regressions that still need to be fixed before the final release. Use the v0.1.x branch for stable releases.

  • 根據(jù)官方的start文檔 修改Cargo.toml 和 main.rs
[dependencies]
tokio = "0.1"
extern crate tokio;

use tokio::io;
use tokio::net::TcpStream;
use tokio::prelude::*;

fn main() {
    // Parse the address of whatever server we're talking to
    let addr = "127.0.0.1:6142".parse().unwrap();
    let client = TcpStream::connect(&addr).and_then(|stream| {
        println!("created stream");
        // Process stream here.
        io::write_all(stream, "hello world\n").then(|result| {
            println!("wrote to stream; success={:?}", result.is_ok());
            Ok(())
        })
    }).map_err(|err| {
        // All tasks must have an `Error` type of `()`. This forces error
        // handling and helps avoid silencing failures.
        // In our example, we are only going to log the error to STDOUT.
        println!("connection error = {:?}", err);
    });

    println!("About to create the stream and write to it...");
    tokio::run(client);
    println!("Stream has been created and written to.");
}
  • 先用 nc 啟動6142端口的監(jiān)聽進程, 然后運行cargo run 可以看到以下狀態(tài)
$ nc -l -p 6142
hello world
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 3.90s
     Running `target/debug/myhello`
About to create the stream and write to it...
created stream
wrote to stream; success=true
Stream has been created and written to.

五 搭建一個http restful服務(wù)

  • 這里我們直接使用框架rocket,類似于node中的express, go里面的gin等。
  • 推薦先讀rocket api文檔
  • 注意 需要使用nightly版本
$ rustup default nightly
$ rustc --version
rustc 1.40.0-nightly (aa69777ea 2019-10-29)
新建項目
$ cargo new management
  • main.rs代碼:
#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}
  • 運行
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 2m 28s                                                          │root@cowkeysu1:/mnt/hgfs/winwork/rust/Rocket# cd ..
     Running `target/debug/management`                                                                                  │root@cowkeysu1:/mnt/hgfs/winwork/rust# cd ..
 Configured for development.                                                                                          │root@cowkeysu1:/mnt/hgfs/winwork# mv^C
    => address: localhost                                                                                               │root@cowkeysu1:/mnt/hgfs/winwork# ls
    => port: 8000                                                                                                       │faf  go  go1.12.12.linux-amd64.tar.gz  ocr  rust  ziliao
    => log: normal                                                                                                      │root@cowkeysu1:/mnt/hgfs/winwork# cd rust/
    => workers: 2                                                                                                       │root@cowkeysu1:/mnt/hgfs/winwork/rust# s
    => secret key: generated                                                                                            │cd s: command not found
    => limits: forms = 32KiB                                                                                            │root@cowkeysu1:/mnt/hgfs/winwork/rust# ls
    => keep-alive: 5s                                                                                                   │hello  myrust  Rocket  rustover
    => tls: disabled                                                                                                    │root@cowkeysu1:/mnt/hgfs/winwork/rust# cd rustover/
  Mounting /:                                                                                                         │root@cowkeysu1:/mnt/hgfs/winwork/rust/rustover# ls
    => GET / (index)                                                                                                    │management  myhello
 Rocket has launched from http://localhost:8000
  • 調(diào)用測試
$ curl http://127.0.0.1:8000
hello,world!
  • 加入GET、POST的方法
    下面的代碼只有不到50行,不過很容易出錯,主要難點還是在rust語法以及Rocket框架的處理上
  • main.rs 代碼:
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] 
extern crate rocket;
#[macro_use] 
extern crate rocket_contrib;
#[macro_use] 
extern crate serde;

use serde::{Serialize, Deserialize};
use rocket::response::status;
use rocket::response::{self,Responder,Response};
use std::io::Cursor;
use rocket::http::{Status, ContentType};
use rocket::request::Request;
use rocket_contrib::json::Json;
use serde_json::json;


#[derive(Serialize)]
struct User {
    id : usize,
    name : String,
    age : i32,
    updated : i64,
}

impl<'r> Responder<'r> for User {
    fn respond_to(self, _: &Request) -> response::Result<'r> {
        Response::build()
            .sized_body(Cursor::new(json!(self).to_string()))
            .header(ContentType::new("application", "json"))
            .ok()
    }
}

#[post("/user/<id>")]
fn addUser(id: usize) -> status::Accepted<String> {
    status::Accepted(Some(format!("id: '{}'", id)))
}

//fn getUser(id: usize) -> Json<User> {
#[get("/user/<id>")]
fn getUser(id: usize) -> User {
    User{
        id:id,
        name:"cowkeys".to_string(),
        age:27,
        updated:0
    }
}

fn main() {
    rocket::ignite().mount("/", routes![addUser,getUser]).launch();
}
  • 運行
$ Cargo run
 Configured for development.
    => address: 0.0.0.0
    => port: 8000
    => log: normal
    => workers: 2
    => secret key: generated
    => limits: forms = 32KiB
    => keep-alive: 5s
    => tls: disabled
  Mounting /:
    => POST /user/<id> (addUser)
    => GET /user/<id> (getUser)
 Rocket has launched from http://0.0.0.0:8000
  • 測試調(diào)用
// GET
curl http://localhost:8000/user/1
id: '1'
// POST
curl -X POST http://localhost:8000/user/1
{"age":19,"id":1,"name":"cowkeys","updated":0}
  • 控制臺會出現(xiàn):
GET /user/1:
    => Matched: GET /user/<id> (getUser)
    => Outcome: Success
    => Response succeeded.
GET /user/1:
    => Matched: GET /user/<id> (getUser)
    => Outcome: Success
    => Response succeeded.
  • 到此,http服務(wù)完成。
總結(jié)

本文介紹了RUST的基礎(chǔ)入門,如何開始使用rust。下篇會從接入數(shù)據(jù)庫開始,一直到使用grpc接入consul服務(wù)發(fā)現(xiàn)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容