RUST例子教程 在线编辑器 mdBook 说明 mdBook 的 GIT 异步编程 文件夹读取文件删除
编码
encoding_rs
1.txt的内容 💖 你好
file = "1.1"
encoding_rs="*"
extern crate file;
use encoding_rs::*;
use std::str;
let mut decoder = encoding_rs::GB18030_INIT.new_decoder();
let bytes = file::get("./1.txt").unwrap();
// let bytes = vec![240, 159, 146, 150];
let sparkle_heart = str::from_utf8(&bytes).unwrap();
rust的windows绑定
https://github.com/microsoft/windows-rs
Rust 字符串
介绍
Rust 中有多种表示字符串的数据类型,其中最常用的是 str 和 String 两种类型。
str 类型
Rust 中有一个表示字符串的原始(primitive)类型 str。str 是字符串切片(slice),每个字符串切片具有固定的大小并且是不可变的。通常不能直接访问 str ,因为切片属于动态大小类型(DST)。所以,只能通过引用(&str)间接访问字符串切片。关于这一点,会在以后的文章中介绍。在下面的内容将不加区分的使用 str 和 &str。
可以通过字符串字面量构造 &str 类型的对象:
let s = "Hello, world!";
在 Rust 中,字符串字面量的类型是 & 'static str,因为它是被直接储存在编译后的二进制文件中的。
还可以使用切片的语法,从一个&str 对象构造出另一个 &str 对象:
let ss = &s[..3];
也可以将切片转换成相应的指针类型:
let p = s as \*const str;
String 类型
像大部分常见的编程语言一样,String 是一个分配在堆上的可增长的字符串类型,它的定义如下:
struct String {
vec: Vec<u8>
}
从源码可以看出,String 是对 Vec
String 保存的总是有效的 UTF-8 编码的字节序列。
构造一个空字符串:
let s = String::new();
还可以通过字符串字面量构造 String 类型的对象:
let hello = String::from("Hello, world!"); String 和 &str 之间有着非常紧密的关系,后者可以用来表示前者的被借用(Borrowed)的副本。
str 和 String 类型的转换
前面已经看到,字符串字面量可以转换成 String。反过来,String 也可以转换成 str。这是通过解引用操作实现的:
impl Deref for String {
fn deref(&self) -> &str {
unsafe { str::from_utf8_unchecked(&self.vec) }
}
}
利用解引用操作就可以将 String 转换成 str:
let s: String = String::from("Hello");
let ss: &str = &s;
String 还可以连接一个 str 字符串:
let s = String::from("Hello");
let b = ", world!";
let f = s + b; // f == "Hello, world!"
如果要连接两个 String 对象,不能简单地直接相加。必须先通过解引用将后一个对象转换为 &str 才能进行连接:
let s = String::from("Hello");
let b = String::from(", world!");
let f = s + &b; // f == "Hello, world!"
注意这里字符串连接之后,s 的所有权发生了转移,而 b 的内容复制到了新的字符串中。
从 String 到 str 的转换是廉价的,反之,从 str 转为 String 需要分配新的内存。
一般来说,当定义函数的参数时, &str 会比 String 更加通用:因为此时既可以传递 &str 对象也可以传递 String 对象。
各种编码转化
&str -> String--| String::from(s) or s.to_string() or s.to_owned()
&str -> &[u8]---| s.as_bytes()
&str -> Vec<u8>-| s.as_bytes().to_vec() or s.as_bytes().to_owned()
String -> &str----| &s if possible* else s.as_str()
String -> &[u8]---| s.as_bytes()
String -> Vec<u8>-| s.into_bytes()
&[u8] -> &str----| s.to_vec() or s.to_owned()
&[u8] -> String--| std::str::from_utf8(s).unwrap(), but don't**
&[u8] -> Vec<u8>-| String::from_utf8(s).unwrap(), but don't**
Vec<u8> -> &str----| &s if possible* else s.as_slice()
Vec<u8> -> String--| std::str::from_utf8(&s).unwrap(), but don't**
Vec<u8> -> &[u8]---| String::from_utf8(s).unwrap(), but don't**
字符串转整数
fn main() { let my_string = "27".to_string(); // `parse()` works with `&str` and `String`! let my_int = my_string.parse::<i32>().unwrap(); println!("{:?}", my_string); println!("{:?}", my_int); }
包含字符串
fn main() { let a="abcd"; println!("{:?}", a.contains("bc")); }
计算字节长度
fn main() { let s1 = "中国-China"; println!("{:?}", s1.len()); // -> 12 let s2 = String::from("中国-China"); println!("{:?}", s2.len()); // -> 12 }
计算字符个数
fn main() { let s1 = "中国-China"; println!("{:?}", s1.chars().count()); // -> 8 let s2 = String::from("中国-China"); println!("{:?}", s2.chars().count()); // -> 8 }
截取指定开始的 n 个的字符
fn substr(s: &str, start: usize, length: usize) -> String { s.chars().skip(start).take(length).collect() } fn main() { let s1 = "中国-China"; println!("{:?}", substr(s1, 1, 100)); println!("{:?}", substr(s1, 0, 2)); let s2 = String::from("中国-China"); println!("{:?}", substr(&s2, 1, 100)); println!("{:?}", substr(&s2, 0, 2)); }
获取指定位置开始的 n 个字节(如果存在非法的字符边界,则返回 None)
fn main() { let mut s = String::from("中国-China"); println!("{:?}", s.get(0..=5)); // -> Some("中国") println!("{:?}", s.get(0..=4)); // -> None }
判断是不是包含某个子串
fn main() { let s1 = "中国-China"; let s2 = String::from("中国-China"); assert_eq!(true, s1.contains("中国")); assert_eq!(true, s2.contains("中国")); }
判断是不是以某个字符串开头
fn main() { let s1 = "中国-China"; let s2 = String::from("中国-China"); assert_eq!(true, s1.starts_with("中国")); assert_eq!(true, s2.starts_with("中国")); }
判断是不是以某个字符串结尾
fn main() { let s1 = "中国-China"; let s2 = String::from("中国-China"); assert_eq!(true, s1.ends_with("China")); assert_eq!(true, s2.ends_with("China")); }
全部转为大写
fn main() { let s1 = "中国-China"; let s2 = String::from("中国-China"); println!("{:?}", s1.to_uppercase()); // -> 中国-CHINA println!("{:?}", s2.to_uppercase()); // -> 中国-CHINA //请注意与 to_uppercase() 的不同 let mut s3 = String::from("中国-China"); s3.make_ascii_uppercase(); println!("{:?}", s3); // -> 中国-CHINA }
全部转为小写
fn main() { let s1 = "中国-China"; let s2 = String::from("中国-China"); println!("{:?}", s1.to_lowercase()); // -> 中国-china println!("{:?}", s2.to_lowercase()); // -> 中国-china //请注意与 to_lowercase() 的不同 let mut s3 = String::from("中国-China"); s3.make_ascii_lowercase(); println!("{:?}", s3); // -> 中国-china }
判断是不是 ASCII 字符串
fn main() { let s1 = "中国-China"; let s2 = "China"; assert_eq!(false, s1.is_ascii()); assert_eq!(true, s2.is_ascii()); }
判断指定位置是不是一个合法的 UTF-8 边界,比如一个汉字的 UTF-8 包含三个字节,那么第一个字节的结束位置必然不是一个合法的 UTF-8 边界(更准确的说,应该是这个位置是不是一个合法字符的开始)
fn main() { let mut s = String::from("中国-China"); assert_eq!(true, s.is_char_boundary(0)); assert_eq!(true, s.is_char_boundary(12)); assert_eq!(false, s.is_char_boundary(2)); assert_eq!(true, s.is_char_boundary(3)); }
字符串替换
fn main() { let mut s = String::from("中国-China"); println!("{:?}", s.replace("中国", "China")); }
字符串切割
fn main() { let mut s = String::from("中国-China"); let result: Vec<&str> = s.split("-").collect(); println!("{:?}", result); // -> ["中国", "China"] }
通过分离: s.split("separator") 通过空白: s.split_whitespace() 通过换行符: s.lines()
trim
fn main() { let s = " Hello\tworld\t"; assert_eq!("Hello\tworld", s.trim()); }
trim_left
fn main() { let s = " Hello\tworld\t"; assert_eq!("Hello\tworld\t", s.trim_left()); }
trim_right
fn main() { let s = " Hello\tworld\t"; assert_eq!(" Hello\tworld", s.trim_right()); }
trim_matches
fn main() { assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); let x: &[_] = &['1', '2']; assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); }
trim_left_matches
fn main() { assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); let x: &[_] = &['1', '2']; assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); }
trim_right_matches
fn main() { assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); let x: &[_] = &['1', '2']; assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); assert_eq!("1fooX".trim_left_matches(|c| c == '1' || c == 'X'), "fooX"); }
其他
fn main() { let a_string = "123foo1bar123".to_string(); let a_str = "123foo1bar123"; let b_string = a_string.replace("123", ""); let b_str = a_str.replace("123", ""); println!("b_string:{:?} b_str:{:?}", b_string, b_str); }
Rust 中的狭义的 Vec,相当于一些其它语言可变长度的 List,ArrayList,Array(Julia 语言),是核心的数据结构。一般通过以下方式生成:
官方文档
fn main() { let vec = vec![1,2,3]; let vec:Vec<i32> =vec![1,2,3];//Vec<i32>也可不加,可以推断出来 let data =Vec::new(); let data:Vec<i32> =Vec::new();//Vec<i32>具体看后面的应用 }
fn main() { let mut vec = vec!["a", "b", "c", "d"];//动态数组 let mut array = ["a", "b", "c", "d"];//固定数组 let mut array:[&str;4] = ["a", "b", "c", "d"];//固定数组: //[&str;4] :其中是分号隔开,4表示这个固定数组的长度,不可变的。 //两者的相同之处: assert_eq!(vec, array);//从目前来看,两者的值是相同的; // 两者的不同之处: //array :可以进行元素数不变下操作,包括改变其中值之类; //array.insert(3,"e");error:没有insert这个函数 //array.push("e"); error:没有push这个函数 // vec: 不限制 }
fn main() { let x = &mut ["a", "b", "c"]; if let Some(elem) = x.get_mut(1) { *elem = "42"; } assert_eq!(x,&["a","42","c"]); }
swap: 交换特定的两个值
fn main() { let mut v = ["a", "b", "c", "d"]; v.swap(1, 3); assert!(v == ["a", "d", "c", "b"]); }
reverse:逆序
fn main() { let mut v = [1, 2, 3]; v.reverse(); assert!(v == [3, 2, 1]); }
iter_mut:循还改值
fn main() { let x = &mut [1, 2, 4]; for elem in x.iter_mut() { *elem += 2; } assert_eq!(x, &[3, 4, 6]); }
#![allow(unused)] fn main() { let mut v = vec![1, 2, 3]; print!("&v "); for x in &v { print!("{} ", x); } println!(" "); print!("len get "); for x in 0..v.len() { if let Some(num) = v.get(x) { print!("{} ", num); } } println!(" "); print!("iter "); for x in v.iter() { print!("{} ", x); } println!(" "); print!("into_iter "); for x in v.into_iter() { print!("{} ", x); } println!(" "); }
windows:有交叉的轮发
fn main() { let slice = ['r', 'u', 's', 't']; let mut iter = slice.windows(2); assert_eq!(iter.next().unwrap(), &['r', 'u']); assert_eq!(iter.next().unwrap(), &['u', 's']); assert_eq!(iter.next().unwrap(), &['s', 't']); assert!(iter.next().is_none()); let slice = ['f', 'o', 'o']; let mut iter = slice.windows(4); assert!(iter.next().is_none()); }
chunks:无交叉的连发
fn main() { let slice = ['l', 'o', 'r', 'e', 'm']; let mut iter = slice.chunks(2); assert_eq!(iter.next().unwrap(), &['l', 'o']); assert_eq!(iter.next().unwrap(), &['r', 'e']); assert_eq!(iter.next().unwrap(), &['m']); assert!(iter.next().is_none()); 再有: let v = &mut [0, 0, 0, 0, 0]; let mut count = 1; for chunk in v.chunks_mut(2) { for elem in chunk.iter_mut() { *elem += count; } count += 1; } assert_eq!(v, &[1, 1, 2, 2, 3]); }
split: 把符合条件的做为分隔
fn main() { let slice = [10, 40, 33, 20]; let mut iter = slice.split(|num| num % 3 == 0); assert_eq!(iter.next().unwrap(), &[10, 40]); assert_eq!(iter.next().unwrap(), &[20]); assert!(iter.next().is_none()); }
contains:包括
fn main() { let v = [10, 40, 30]; assert!(v.contains(&30)); assert!(!v.contains(&50)); }
starts_with,end_with:以…开始(结尾)
fn main() { let v = [10, 40, 30]; assert!(v.starts_with(&[10])); assert!(v.starts_with(&[10, 40])); assert!(!v.starts_with(&[50])); assert!(!v.starts_with(&[10, 50])); //注意: let v = &[10, 40, 30]; assert!(v.starts_with(&[])); let v: &[u8] = &[]; assert!(v.starts_with(&[])); }
sort,sort_by,sort_by_key:排序
fn main() { let mut v = [-5, 4, 1, -3, 2]; v.sort(); assert!(v == [-5, -3, 1, 2, 4]); let mut v = [5, 4, 1, 3, 2]; v.sort_by(|a, b| a.cmp(b)); assert!(v == [1, 2, 3, 4, 5]); // reverse sorting v.sort_by(|a, b| b.cmp(a)); assert!(v == [5, 4, 3, 2, 1]); let mut v = [-5i32, 4, 1, -3, 2]; v.sort_by_key(|k| k.abs()); assert!(v == [1, 2, -3, 4, -5]); }
to_vec(),into_vec()
fn main() { let s = [10, 40, 30]; let x = s.to_vec(); // Here, `s` and `x` can be modified independently. let s: Box<[i32]> = Box::new([10, 40, 30]); let x = s.into_vec(); // `s` cannot be used anymore because it has been converted into `x`. assert_eq!(x, vec![10, 40, 30]); }
insert,在相应个序号上 insert
fn main() { let mut v = vec!["a", "b", "c"]; v.insert(1, "d");//在第1个序列号上insert 元素"d" assert_eq!(v, vec!["a", "d", "b", "c"]); // 值相等,再次举例 assert_eq!(v, ["a", "d", "b", "c"]); }
remove,删除第 n 个值
fn main() { let mut v = vec!["a", "b", "c"]; assert_eq!(v.remove(1), "b");//删除第1个值(0,1,....) }
retain: 只保留符合条件的值
fn main() { let mut vec = vec![1, 2, 3, 4]; vec.retain(|&x| x%2 == 0); assert_eq!(vec, [2, 4]); }
push、pop、append
fn main() { // push:对元素的压入操作 let mut vec = vec![1, 2]; vec.push(3); assert_eq!(vec, [1, 2, 3]); //pop:对元素的弹出操作,后进先出型 let mut vec = vec![1, 2, 3]; assert_eq!(vec.pop(), Some(3)); assert_eq!(vec, [1, 2]); // append :两个vec之间 let mut vec = vec![1, 2, 3]; let mut vec2 = vec![4, 5, 6]; vec.append(&mut vec2); assert_eq!(vec, [1, 2, 3, 4, 5, 6]); assert_eq!(vec2, []); }
is_empty(), len
fn main() { let mut v = Vec::new(); assert!(v.is_empty()); v.push(1); assert!(!v.is_empty()); let a = vec![1, 2, 3]; assert_eq!(a.len(), 3); }
drain、clear
fn main() { // 抽取序列号满足条件的,组成新的vec let mut v = vec![1, 2, 3]; let u: Vec<_> = v.drain(1..).collect(); assert_eq!(v, &[1]); assert_eq!(u, &[2, 3]); // drain(..)==clear() v.drain(..); assert_eq!(v, &[]); assert!(v.is_empty()); // clear() let mut v = vec![1, 2, 3]; v.clear(); assert!(v.is_empty()); }
truncate :截取前面<n 的值
fn main() { let mut n =3; let mut vec = vec!["a", "b", "c", "d", "e"]; vec.truncate(n);//取0,1,2序列值 assert_eq!(vec, ["a", "b", "c"]); //如果n>vec.len()-1,则会报错 }
extend、extend_from_slice
fn main() { //extend let mut vec = vec![4, 5, 6]; vec.extend([1, 2, 3].iter().cloned());//[4,5,6,1,2,3] vec.sort(); println!("vec :{:?}", vec); //[1,2,3,4,5,6] //extend_from_slice let mut vec = vec![1]; vec.extend_from_slice(&[2, 3, 4]); assert_eq!(vec, [1, 2, 3, 4]); }
rustup show
cargo +nightly build --release --target=x86_64-pc-windows-msvc --verbose --verbose
- 生命周期
用 Fn 特征解决闭包生命周期
fn main() {
let x = 3;
let closure_slision = fun(|x: &i32| -> &i32 {
println!("{}", x);
x
});
closure_slision(&x);
}
fn fun<T, F: Fn(&T) -> &T>(f: F) -> F {
f
}
struct MyStruct {
s: String,
}
impl Copy for MyStruct {}
fn main() {
let s1 = MyStruct { s: String::from("hello") };
let s2 = s1; // 编译错误!
println!("{}, {}", s1.s, s2.s);
}
以上代码将无法编译并出现以下错误:
|
4 | impl Copy for MyStruct {}
| ^^^^ `std::string::String` cannot be copied
...
7 | let s2 = s1; // 编译错误!
| -- value moved here
...
为了让MyStruct支持Copy trait,可以将String类型改为&str类型作为结构体字段类型,代码如下:
struct MyStruct<'a> {
s: &'a str,
}
impl<'a> Copy for MyStruct<'a> {}
fn main() {
let s1 = MyStruct { s: "hello" };
let s2 = s1;
println!("{}, {}", s1.s, s2.s);
}
在这个例子中,我们使用了一个引用来代替堆分配的String类型。同时,由于我们使用了引用类型,我们需要为MyStruct定义一个生命周期来防止出现借用错误。