RUST有毒,如何从零开始到接入微服务集群 第一章

前言

RUST:

  • 适合编程初学者学习、当前适合当团队的语言选型对象、优雅
  • 适合学习、适合准备、适合强迫症、适合
缺点
  • 1 上手困难,相对其他语言有较复杂的语法和理念,门槛比较高
  • 2 有很多独有表达式,可读性较差
  • 3 严格的语法限制,如作用域、生命周期等,学习成本高
  • 4 目前版本不统一,stable和nightly版本区别较大
  • 5 不好做语言迁移,生态还不完全
优点
  • 1 有毒,容易上瘾
  • 2 社区开发速度快,现在是个学习的好时候,目前,保持着每 6 周更新一次的节奏。Rust 发布的工具链包括了 stablebetanightly 三种不同版本。 nightly 是最激进的版本,包含了大量(可能不稳定)的新/高级特性。stable 版本目前可能还不支持一些高级特性。beta 介于两者之间。
  • 3 从语言层面就减少各种开销和数据竞争,更加安全
  • 4 性能

参考资料

官方中文网站
crates 库类搜索
简体中文文档
语法基础教程
RUST 特性分析 by austenliao
Rust中文社区
tokio文档
Rocket文档

必看语法

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

目录

  • 安装RUST
  • hello world
  • 使用第三方库
  • 测试socket stream
  • 搭建http服务
  • 数据库操作
  • 与golang的压测对比
  • 接入基于consul的grpc微服务集群

一 安装RUST

  • 下载
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • 激活环境
source $HOME/.cargo/env
  • 检查是否安装成功
$ cargo --version
cargo 1.38.0 (23ef9a4ef 2019-08-20)

cargo 命令介绍

  • cargo build 可以构建项目
  • cargo run 可以运行项目
  • cargo test 可以测试项目
  • cargo doc 可以为项目构建文档
  • cargo publish 可以将库发布到 crates.io

二 helloworld

$ cargo new myhello
  • 生成的文件结构
$ 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.
  • 失败了,新装的虚拟机环境不够完全,注意最好换成aliyun的源再继续
$ 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目录中找到可执行文件
$ 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 会指向官方文档网站
Repository 会指向github

  • tokio 异步编程框架是使用人数较多的框架,不仅是引用量和下载量都是最高的,而且是官方支持的项目。但是rust生态目前还不是很完善,因此很多项目都不稳定,从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.

  • 根据官方的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端口的监听进程, 然后运行cargo run 可以看到以下状态
$ 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服务

  • 这里我们直接使用框架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
  • 调用测试
$ 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
  • 测试调用
// 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}
  • 控制台会出现:
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服务完成。
总结

本文介绍了RUST的基础入门,如何开始使用rust。下篇会从接入数据库开始,一直到使用grpc接入consul服务发现。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容