Obeta

Rust常用的一些编程方法与技巧

在一些其他语言中常见的使用方法,到了Rust中后就不知道如何去实现,这是初学者经常会遇到的一个问题,因此这里收集一下这类snippet,方便随时查看.

以下的例子都可以执行,你可以去play-rust验证以下.

本文将不定时持续更新.

类型转换

这是一种很常见的需求,尤其在静态语言中必须强制手动转换,否则就会编译错误.

string -> f32

let value = "0.11";
let f = value.parse::<f32>(); // returns an Result<f32>

if let Ok(v) = f {
	// get v
	println!("{}", v);
}

// or

match f {
	Ok(value) => println!("{}", v),
	Err(error) => panic!("{} value is not a number, unable to convert to f32"),
}

str -> char

let comma: &str = ",";
let my_char = comma.chars().next().expect("string is empty");
// let my_char = comma.chars().nth(0).unwrap(); // unsafe, if the string is empty, your program will panic

assert_eq!(my_char, ',');

str -> string

// 1
let new_string = String::from("Hello World!");

// 2
let new_string = "Hello World!".to_string();

// 3
let new_string = "Hello World!".to_owned();

// 4
let mut new_string = String::new(); //Create an empty string
new_string.push_str("Hello");
new_string.push_str(" World!");

// 5
let world_var= "world";
//Becomes "Hello World!"
let new_string = format!("Hello {}!", world_var);

string -> str

// 1
let my_string = String::from("Hello World!");
let my_immutable_string = &my_string; //This is a &String type
let my_str: &str = &my_string; //This is an &str type

// 2
let s: String = "abcdefg".to_owned();
let s_slice: &str = &s[..];  // take a full slice of the string

let s_slice: &str = &*s;  // s  : String
                          // *s : str (via Deref<Target=str>)
                          // &*s: &str

string -> Vec<char>

let s = "Hello world!";
let char_vec: Vec<char> = s.chars().collect();
for c in char_vec {
	println!("{}", c);
}

string -> Vec<&str>

let s = "Hello world!";
let mut char_vec: Vec<&str> = s.split("").collect();
char_vec.retain(|&x| x != "");
println!("{:?}", char_vec); // ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "!"]

string <-> f32

先来看一下: string -> f32.

let s = "5.7".to_owned();
let d = match s.parse::<f32>() { // `i32`,`i64`,`f32`,`f64` etc...
	Ok(value) => value,
	Err(_error) => panic!("value is not a number, unable to convert to f32"),
}
// `parse()` works with `&str` and `String`!
let d = s.parse::<f32>().unwrap();

f32 -> string

let d = 3i32;
println!("{}", d.to_string());

let d1 = 3.5f32;
println!("{}", d1.to_string());

f32 <-> i32

数字类型直接的转换还是挺简单的,使用一个关键字as:

let from = 2.3f32 as i32;
let to = 2i32 as f32;

还有其它的一些转换可以在Rust String Conversions找到.

vec 操作

  1. 声明
let mut vec = Vec::new();

let vec1 = vec![1, 2, 3, 4];
let vec2 = vec![0; 5]; // [0, 0, 0, 0, 0]
  1. 增加值
let mut vec = Vec::new();

vec.push(1);
vec.push(2);
vec.push(3);
vec.push(4);
  1. 移除最后一个值
let mut vec = vec![1, 2, 3, 4];
let value = vec.pop();

if let Some(v) = value {
	assert_eq!(v, 4);
}
  1. 循环
let mut vec = vec![1, 2, 3, 4];

for x in &vec {
	println!("{}", x);
}
while let Some(top) = vec.pop() {
	// Prints 3, 2, 1
	println!("{}", top);
}
  1. 查找 vec 里最大最小值

最大值:

let vec = vec![1, 2, -3, 4];
let vec1: Vec<u32> = Vec::new();

assert_eq!(vec.iter().max(), Some(&4));
assert_eq!(vec1.iter().max(), None);

最小值:

let vec = vec![1, 2, -3, 4];
let vec1: Vec<u32> = Vec::new();

assert_eq!(vec.iter().min(), Some(&-3));
assert_eq!(vec1.iter().min(), None);

当 vec 里不是数字类型,那么需要使用max_by_key,max_by这类,这类方法接受一个匿名函数,返回Ordering类型:

let vec = vec![1i32, 2, -3, 4]; // 加上i32,否则下面`x.abs`会报错(rust中默认不加类型的数字都是usize,此类型都是无符号类型,因此没有abs方法),或者使用下面这行声明
// let vec: Vec[i32] = vec![1, 2, -3, 4];

assert_eq!(*vec.iter().max_by_key(|x| x.abs()).unwrap(), 4);
assert_eq!(*vec.iter().max_by(|x, y| x.cmp(y)).unwrap(), 4);

assert_eq!(*vec.iter().min_by_key(|x| x.abs()).unwrap(), 1);
assert_eq!(*vec.iter().min_by(|x, y| x.cmp(y)).unwrap(), -3);

如果 vec 是浮点类型,那么应该使用partial_cmp

  1. 搜索值返回索引
let vec = vec![1, 2, -3, 4];

assert_eq!(vec.iter().position(|&x| x == 2), Some(1));
assert_eq!(vec.iter().position(|&x| x == 5), None);

返回找到第一个符合要求的元素索引,还可以继续搜索:

let vec = vec![1, 2, -3, 4];
let mut iter = vec.iter();

assert_eq!(iter.position(|&x| x >= 2), Some(1));
assert_eq!(iter.next(), Some(&-3)); // 返回下一个值
assert_eq!(iter.position(|&x| x == 4), Some(0)); // 返回索引依赖于迭代器当前状态

position是从左开始搜索,而rposition是从右开始.

小数精度

有时候需要格式一些很长的浮点数,但是 rust 值提供了round方法,这个方法移除所有的小数,因此并不能直接使用,那么可以使用下面这个我提供的函数:

// value: 需要格式化的f32
// digit: 需要格式的精度
fn round(value: f32, digit: u32) -> f32 {
	let a = 10usize.pow(digit) as f32;

	(value * a).round() / a
}

println!("{}", round(3.456f32, 2));

可以点击这里运行查看.

命令行获取参数

use std::env;

fn main() {
 let args: Vec<_> = env::args().collect();
 if args.len() > 1 {
  println!("The first argument is {}", args[1]);
 }
}

或者直接通过standard iterator toolbox获取:

use std::env;

fn main() {
 if let Some(arg1) = env::args().nth(1) {
		println!("The first argument is {}", arg1);
 }
}

也可以使用社区提供的一些工具:

个人随笔记录,内容不保证完全正确,若需要转载,请注明作者和出处.