列举常用的一些功能的demo或者实现形式。
use std::fs;
use std::env;
fn main() {
println!("curdir: {}, curexe: {}", env::current_dir().unwrap().display(), env::current_exe().unwrap().display());
println!("cd to ../..\n");
env::set_current_dir("../..").unwrap();
println!("ls: {}", env::current_dir().unwrap().display());
let paths = fs::read_dir("./").unwrap();
for path in paths {
let f = path.unwrap().path();
println!("{} {}", if f.is_file() { "f" } else { "d" }, f.display());
}
}
这个没有官方的包,需要使用第三方 sys-info.
获取信息十分有限。
extern crate sys_info;
fn main() {
println!("操作系统:{}", sys_info::os_type().unwrap());
println!("版本:{}", sys_info::os_release().unwrap()); // win10 is 6.2
println!("名称:{}", sys_info::hostname().unwrap());
println!("CPU个数:{}", sys_info::cpu_num().unwrap());
println!("CPU速度:{:.2}GHz", sys_info::cpu_speed().unwrap() as f64 / 1024.0);
println!("平均负载:{:.2}%", sys_info::loadavg().unwrap().one * 100.0);
let minfo = sys_info::mem_info().unwrap();
println!("内存信息:{:.2}G/{:.2}G free", minfo.total as f64/1024.0/1024.0, minfo.free as f64/1024.0/1024.0);
let dinfo = sys_info::disk_info().unwrap();
println!("当前磁盘分区信息:{:.2}G/{:.2}G free", dinfo.total as f64/1024.0/1024.0, dinfo.free as f64/1024.0/1024.0);
}
use std::io;
use std::io::prelude::*;
fn main() {
let mut input = String::new();
println!("test io input.");
io::stdout().write("put your code: ".as_bytes()).unwrap();
io::stdout().flush().unwrap();
io::stdin().read_line(&mut input).unwrap();
println!("your input: {}", input);
}
// try! 和 ? 作用雷同,都需要在父函数中返回Result才能使用。
use std::io;
use std::io::prelude::*;
fn main() {
let a = (1..5).collect::>();
for i in &a {
println!("1 {}", i);
}
a.into_iter().for_each(|v| {
println!("2 {}", v)
});
let m = (1..20).fold(0u64, |x, y| y + x);
println!("{}", m);
let m = (1..20).map(|x| 10 * x);
println!("{}", m);
let m = (1..20).filter(|x| x%3 == 0);
println!("{}", m);
}
extern crate clap;
use clap::{Arg, App, SubCommand};
fn main() {
let matches = App::new("My Super Program")
.version("1.0")
.author("Kevin K. ")
.about("Does awesome things")
.arg(Arg::with_name("config")
.short("c")
.long("config")
.value_name("FILE")
.help("Sets a custom config file")
.takes_value(true))
.arg(Arg::with_name("INPUT")
.help("Sets the input file to use")
.required(true)
.index(1))
.arg(Arg::with_name("v")
.short("v")
.multiple(true)
.help("Sets the level of verbosity"))
.subcommand(SubCommand::with_name("test")
.about("controls testing features")
.version("1.3")
.author("Someone E. ")
.arg(Arg::with_name("debug")
.short("d")
.help("print debug information verbosely")))
.get_matches();
// Gets a value for config if supplied by user, or defaults to "default.conf"
let config = matches.value_of("config").unwrap_or("default.conf");
println!("Value for config: {}", config);
// Calling .unwrap() is safe here because "INPUT" is required (if "INPUT" wasn't
// required we could have used an 'if let' to conditionally get the value)
println!("Using input file: {}", matches.value_of("INPUT").unwrap());
// Vary the output based on how many times the user used the "verbose" flag
// (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
match matches.occurrences_of("v") {
0 => println!("No verbose info"),
1 => println!("Some verbose info"),
2 => println!("Tons of verbose info"),
3 | _ => println!("Don't be crazy"),
}
// You can handle information about subcommands by requesting their matches by name
// (as below), requesting just the name used, or both at the same time
if let Some(matches) = matches.subcommand_matches("test") {
if matches.is_present("debug") {
println!("Printing debug info...");
} else {
println!("Printing normally...");
}
}
// more program logic goes here...
}
// rsdemo.exe i.txt -v -v test -d
// winapi={ version = "", features = ["winuser"] }
#[cfg(windows)] extern crate winapi;
use std::io::Error;
#[cfg(windows)]
fn print_message(msg: &str) -> Result {
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
use winapi::um::winuser::{MB_OK, MessageBoxW};
let wide: Vec = OsStr::new(msg).encode_wide().chain(once(0)).collect();
let ret = unsafe {
MessageBoxW(null_mut(), wide.as_ptr(), wide.as_ptr(), MB_OK)
};
if ret == 0 { Err(Error::last_os_error()) }
else { Ok(ret) }
}
#[cfg(not(windows))]
fn print_message(msg: &str) -> Result<(), Error> {
println!("{}", msg);
Ok(())
}
fn main() {
print_message("Hello, world!").unwrap();
}
let parsed = json::parse(r#"
{
"code": 200,
"success": true,
"payload": {
"features": [
"awesome",
"easyAPI",
"lowLearningCurve"
]
}
}
"#).unwrap();
let instantiated = object!{
"code" => 200,
"success" => true,
"payload" => object!{
"features" => array![
"awesome",
"easyAPI",
"lowLearningCurve"
]
}
};
assert_eq!(parsed, instantiated);
服务器端:
在目前状态下(2019-2-21)基本没有太多可选的,大部分web框架都依赖tokio执行,其中功能比较完善的是actix系列。
mysql
#[macro_use]
extern crate mysql;
// ...
use mysql as my;
#[derive(Debug, PartialEq, Eq)]
struct Payment {
customer_id: i32,
amount: i32,
account_name: Option,
}
fn main() {
// See docs on the `OptsBuilder`'s methods for the list of options available via URL.
let pool = my::Pool::new("mysql://root:password@localhost:3307/mysql").unwrap();
// Let's create payment table.
// Unwrap just to make sure no error happened.
pool.prep_exec(r"CREATE TEMPORARY TABLE payment (
customer_id int not null,
amount int not null,
account_name text
)", ()).unwrap();
let payments = vec![
Payment { customer_id: 1, amount: 2, account_name: None },
Payment { customer_id: 3, amount: 4, account_name: Some("foo".into()) },
Payment { customer_id: 5, amount: 6, account_name: None },
Payment { customer_id: 7, amount: 8, account_name: None },
Payment { customer_id: 9, amount: 10, account_name: Some("bar".into()) },
];
// Let's insert payments to the database
// We will use into_iter() because we do not need to map Stmt to anything else.
// Also we assume that no error happened in `prepare`.
for mut stmt in pool.prepare(r"INSERT INTO payment
(customer_id, amount, account_name)
VALUES
(:customer_id, :amount, :account_name)").into_iter() {
for p in payments.iter() {
// `execute` takes ownership of `params` so we pass account name by reference.
// Unwrap each result just to make sure no errors happened.
stmt.execute(params!{
"customer_id" => p.customer_id,
"amount" => p.amount,
"account_name" => &p.account_name,
}).unwrap();
}
}
// Let's select payments from database
let selected_payments: Vec =
pool.prep_exec("SELECT customer_id, amount, account_name from payment", ())
.map(|result| { // In this closure we will map `QueryResult` to `Vec`
// `QueryResult` is iterator over `MyResult` so first call to `map`
// will map each `MyResult` to contained `row` (no proper error handling)
// and second call to `map` will map each `row` to `Payment`
result.map(|x| x.unwrap()).map(|row| {
// ⚠️ Note that from_row will panic if you don't follow your schema
let (customer_id, amount, account_name) = my::from_row(row);
Payment {
customer_id: customer_id,
amount: amount,
account_name: account_name,
}
}).collect() // Collect payments so now `QueryResult` is mapped to `Vec`
}).unwrap(); // Unwrap `Vec`
// Now make sure that `payments` equals to `selected_payments`.
// Mysql gives no guaranties on order of returned rows without `ORDER BY`
// so assume we are lukky.
assert_eq!(payments, selected_payments);
println!("Yay!");
}
比较建议使用Rust做后端+WebAssembly, 然后调用本地webview显示界面,提供特定功能。
参考:
azul
imgui
*hwgui
Servo RUST做的渲染引擎。
https://rustwasm.github.io/book/game-of-life/introduction.html
image
extern crate image;
use image::GenericImageView;
fn main() {
// Use the open function to load an image from a Path.
// ```open```returns a `DynamicImage` on success.
let img = image::open("test.jpg").unwrap();
// The dimensions method returns the images width and height.
println!("dimensions {:?}", img.dimensions());
// The color method returns the image's `ColorType`.
println!("{:?}", img.color());
// Write the contents of this image to the Writer in PNG format.
img.save("test.png").unwrap();
}
ffmpeg
ffmpeg-sys
use std::rc::Rc;
use std::cell::{RefCell, Cell};
#[derive(Debug)]
struct MyArg {
pub arg0: i32,
pub arg1: Cell, // 不用mut, 直接set/replace
pub arg2: RefCell, // 需要mut,然后修改
// pub arg3: Cell, // Error, Cell要求必须实现Copy
}
fn main() {
let a = Rc::new(MyArg {
arg0: 0,
arg1: Cell::new(10) ,
arg2: RefCell::new("231".to_string()),
});
dbg!(&a);
a.arg1.replace(20);
// a.arg0 = 11; // can't do this
a.arg2.borrow_mut().push_str("======");
dbg!(&a);
}
extern crate futures;
use futures::prelude::*;
use futures::Future;
use futures::future;
use std::result;
use std::io::Error;
// Option, Box, Future, Result
fn t1(a: i32) -> Option {
if a > 10 {
Some(a)
} else {
None
}
}
fn t2(a: i32) -> Result {
if a > 10 {
Ok(a)
} else {
Err("a is too small".to_string())
}
}
fn my_fn() -> Result> {
Ok(100)
}
fn my_fut() -> impl Future- > {
future::ok(100)
}
fn main() {
// Option 用法和解法
println!("{:?}", t1(11).unwrap());
println!("{:?}", t1(3).unwrap_or_else(|| -1));
// Result 用法和解包
// ? 操作符可以简化Result类型返回值的传递,最终解包还需手动
println!("{:?}", t2(12).unwrap_or_default());
let x = match t2(6) {
Ok(v) => v,
Err(_) => 0,
};
println!("{:?}", x);
let x = t2(2).unwrap_or_else(|_| -1);
println!("{:?}", x);
// future 用法和解包
// Rust 的 futures 其實就是 Results:也就是說你需要指定預期返回類型和錯誤類型。
let f1 = my_fn();
println!("{:?}", f1.unwrap_or(0));
let f2 = my_fut();
println!("{:?}", f2.wait().unwrap_or(0)); // wait 执行
// 尴尬的是,目前的rust除了wait没有好的办法执行future。等待await出来后可能会好点。
// 目前一般做法是使用pool跑,然后接收返回。建议使用tokio来做这些事。
// Box 只是一个指针,可以直接访问。
}
// 传指针(引用)
fn fuc1( arg1: &mut i32 ){
*arg1 = 2;
println!("fuc1 {}", arg1);
}
// 传值
fn fuc2(mut arg1: i32){
arg1 = 3;
println!("fuc2 {}", arg1);
}
fn main() {
let mut a = 10;
fuc1(&mut a); // 匹配&mut i32类型,传递的是指针
println!("{}", a); // 2
fuc2(a); // 匹配mut i32,但是mut是函数内arg1可变,仍然传值
println!("{}", a); // 2
}
fn main() {
let mut x = &mut 5_i32;
println!("{:p} {}", x, x);
let mut a = 10;
x = &mut a; // x 指针赋值
println!("{:p} {}", x, x);
*x = 12; // x指针指向的内存赋值
println!("{:p} {}", x, x);
}
/*
0xebd031f7b4 5
0xebd031f82c 10
0xebd031f82c 12
*/
mut x
表示x变量是可变的,更改方式为x=&mut a;
,&mut 5_i32
表示x指向一个i32指针,并且这个指针指向的内存区域存储的值可以更改,更改方法为*x = 12;
。
Copy内部没有方法,只是一个空的trait,必须有Clone才能实现Copy。给编译器采用,改变move行为的。如果一个结构体需要Copy,则其每个成员必须实现Copy.
Copy一般要求可以使用memcpy直接复制,而带有drop语义的一般不能实现Copy.
Clone需要实现具体的内容,内有2个方法。给编码者主动调用。任何类型都可实现Clone。
自动生成工具:#[derive(Clone,Copy)]
在Rust中编写析构函数方法是实现impl std::ops::Drop
trait Drop{
fn drop(&mut self);
}
RUST的RAII通常在使用资源时,不需要手动关闭或者释放,依赖生存周期,自动完成。
use std::fs::File;
use std::io::Read;
fn main() {
let f = File::open("/target/file/path");
if f.is_err() {
println!("file is not exist.");
return;
}
let mut f = f.unwrap();
let mut content = String::new();
let result = f.read_to_string(&mut content);
if result.is_err() {
println!("read file error.");
return;
}
println!("{}", result.unwrap());
}
生命周期提前结束可以使用std::mem::drop()
方法主动结束。
除了move,clone,变量还可以被借用,&
表示只读借用,&mut
表示读写借用。借用指针也被称为引用ref。
借用指针与普通指针内部是一样的,只在语义上有区别。
共享不可变,可变不共享
&
称为共享型指针,可多个存在&mut
称为独占型指针,只能存在一个Rc是智能指针,只能共享访问存储内容,不能修改。
Cell具有内部可变性,不仅可以访问,还可以修改其存储内容。限制是通过get_mut()
只能在Life time内存在一个可变访问。
RefCell同Cell,但是通过borrow/borrow_mut
可以提供Ref
提供多个可读写对象使用。
Rust中提供了只读引用的类型有&、Rc、Arc
等指针,它们可以提供alias。Rust中提供了内部可变性的类型有Cell、RefCell、Mutex、RwLock
以及Atomic*
系列类型等。这两类类型经常需要配合使用。
如果你需要把一个类型T封装到内部可变性类型中去,要怎样选择Cell和RefCell呢?
原则就是,如果你只需要整体性地存入、取出T,那么就选Cell。如果你需要有个可读写指针指向这个T修改它,那么就选RefCell。
Cow(Copy on write)当资源写入时才进行复制,否则是借用。
需要提醒大家注意的是,“取引用”操作符,如&、&mut,是不允许重载的。
因此,“取引用”和“解引用”并非对称互补关系。*&T
的类型一定是T,而&*T
的类型未必就是T。