前言
RUST:
- 不适合编程初学者学习、当前不适合当团队的语言选型对象、不优雅
- 适合学习、适合准备、适合强迫症、适合玩
缺点
- 1 上手困难,相对其他语言有较复杂的语法和理念,门槛比较高
- 2 有很多独有表达式,可读性较差
- 3 严格的语法限制,如作用域、生命周期等,学习成本高
- 4 目前版本不统一,stable和nightly版本区别较大
- 5 不好做语言迁移,生态还不完全
优点
- 1 有毒,容易上瘾
- 2 社区开发速度快,现在是个学习的好时候,目前,保持着每 6 周更新一次的节奏。Rust 发布的工具链包括了
stable
、beta
和nightly
三种不同版本。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 可以搜索需要用到的库
注意:
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 thev0.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服务发现。