语言内置类型:
- 基础类型:Boolean, Numeric, Textual, Never;
- 序列类型:Tuple, Array, Slice;
- 自定义类型:Struct, Enum, Union;
- 函数类型:Functions, Closures;
- 指针类型:References, Raw pointers, Function pointers;
- Trait 类型:Trait objects, impl Trait;
注:String、Vec 是标准库类型,而非语言内置类型。
栈变量类型:基础类型, array/struct/tuple/enum/union;
堆变量类型:
- 字符串:String;
- 容器:Vec/HashMap/HashSet;
- Slice;
- 智能指针:Box/Rc/Arc/Cell/RefCell;
类型别名(type alias):并没有引入新类型,可以按照原类型的方式使用别名类型。
type Meters = u32;
let x: u32 = 5;
let y: Meters = 5;
// Meters 是 u32 的 alias,支持 u32 类型的所有操作。
println!("x + y = {}", x + y);
// 使用 type alias 来提升代码可读性
type Thunk = Box<dyn Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("hi"));
fn takes_long_type(f: Thunk) {}
fn returns_long_type() -> Thunk {}
// type alias 支持泛型参数
type Result<T> = std::result::Result<T, std::io::Error>;
1 scalar #
Scalar 类型:
- signed integers: i8, i16, i32, i64, i128, isize, 默认推断 i32;
- unsigned integers: u8, u16, u32, u64, u128, usize;
- floating point: f32, f64, 默认推断 f64;
- char: Unicode 字符 (占用 4 byte, UTF-32),如 ‘a’, ‘α’,’∞’;
- bool: true/false, 占用 1 byte;
- the unit type () : 只有一个空值
()
; - Never: !
单元类型 Unit Type:() 是类型和唯一值,作为函数的返回类型时表明不返回任何数据:
// 隐式返回单元类型 ()
fn print_message() {
println!("Hello, world!");
}
fn main() {
println!("{:p}, {:p}", &(), &()); // 打印地址相同, 说明是唯一类型值
print_message();
// 显式使用单元类型和单元值
let my_unit: () = ();
// 函数参数接受单元类型值
take_unit(());
// 泛型类型也可以使用单元类型
let result: Result<(), &str> = Ok(());
match result {
Ok(_) => println!("Operation was successful."),
Err(e) => println!("Error occurred: {}", e),
}
}
字面量可以加类型后缀, 如 23u8, 12.3f64
,数字/类型后缀之间可以加下划线, 如
2_3_u8
等效于 23u8
。使用 0b/0o/0x
表示整型(只能使用小写字母前缀)。
fn main() {
let remainder = 43.0 % 5.0; // 浮点取模运算, 截断除法
let logical: bool = true;
let a_float: f64 = 1.0;
let an_integer = 5i32;
// 缺省推断:整型推断为 i32,浮点数推断为 f64
let default_float = 3.0; // f64
let default_integer = 7; // i32
// 类型推导(从后续的赋值语句推导出类型为 i64)。
let mut inferred_type = 12;
inferred_type = 4294967296i64;
let mut mutable = 12;
mutable = 21;
// Error! The type of a variable can't be changed.
//mutable = true;
// 变量可以被 shodow(重新定义类型和可变性)
let mutable = true;
}
整数溢出:执行 debug
构建的二进制时整数溢出并 panic。执行 release 构建的二进制时溢出不会被检查,会导致 “环绕” 行为。
fn main() {
let x: u8 = 255;
// 使用 wrapping_add 可以防止 panic
let y: u8 = x.wrapping_add(1);
println!("y: {}", y);
// 输出: y: 0
}
Rust 不会为原始类型做隐式的转换,需要使用 as
表达式来显式转换。 as
是后缀运算符,优先级非常高。类型转换时,浮点数转换为整数时小数部分将被截断(不进行四舍五入)。
fn main() {
let decimal = 97.123_f32;
let integer: u8 = decimal as u8;
let c1: char = decimal as char;
let c2 = integer as char;
let integer: u32 = 5;
let float: f64 = 3.0;
let int_to_float = integer as f64; // 5.0
// 浮点数转换为整数,小数部分被截断
let float_to_int = float as u32; // 3
}
as 只能用于 primitive 或者 type coercion 类型的转换;
// let val: Box<dyn Any + 'a> = *val as Box<dyn Any + 'a>; // 错误
// OK: circle 可以 usized 协变到 dyn Circle
let circle = Box::new(circle) as Box<dyn Circle>;
let a = *const [u16] as *const [u8]
复杂类型使用 From/Into/TryFrom/TryInto/AsRef/AsMut 等 trait
来进行类型转换:
from()
用于无风险的转换,它不会产生错误,但是可能会 panic;try_from()
返回 Result 类型,当转换失败时(例如,因为类型溢出或数据丢失)返回错误,可以显式检查和处理。
// From/Into 由标准库 prelude 自动导入,不需要手动导入。
use std::convert::TryInto; // 需要先导入 Trait
fn main() {
let decimal = 65.4321_f64;
// 使用 TryInto trait 的 try_into 方法进行安全转换
let integer: u8 = decimal.try_into().unwrap_or_default();
// 使用 From trait 进行结果检查的安全转换
let integer_from = u8::from(42);
let string_from = String::from("just for test");
// 字符串的 parse::<T>() 方法可以将字符串解析转换为其它类型值。
// parse 基于 FromStr trait 实现。
let i77 = "123".parse::<i32>().unwrap();
let i77: i32 = "123".parse().unwrap();
}
2 textual #
textual
类型: char/str/String/OsStr/OsString/CStr/CString/Path/PathBuf
char
是 4 bytes Unicode 字符码点(UTF-32), 使用 as 将 char 转换为 u8、u32 整型的字符码点, 使用 std::char::from_u32()
将码点转换为 char。
fn main() {
let emoji: char = '😂';
let chinese_character: char = '中';
let word = "Rust语言";
for ch in word.chars() {
println!("{}", ch);
}
// 将字符转换为对应的 Unicode 代码点
let unicode_codepoint = '🦀' as u32;
println!("The Unicode code point of '🦀' is: U+{:X}", unicode_codepoint);
let character_from_codepoint = std::char::from_u32(unicode_codepoint)
.unwrap_or_default();
println!("The character from code point U+{:X} is: '{}'",
unicode_codepoint, character_from_codepoint);
}
str 是一块连续的 u8 byte 内存,保存 UTF-8 编码的字符串。str 编译时大小未知,一般不能直接作为变量类型,而使用固定大小类型的 &str
或智能指针 Box/Cow/Rc<str>
类型:
- &str 是 fat pointer 类型,占用两个usize 内存,包括指向内存区域的指针和 byte 数量;
use std::slice;
use std::str;
let hello_world = "Hello, World!";
// 等效于
let hello_world: &'static str = "Hello, world!";
// 使用 &'static str 可以避免为 struct 指定 lifetime 参数
struct Anime {
name: &'static str,
bechdel_pass: bool
};
let aria = Anime {
name: "Aria: The Animation",
bechdel_pass: true
};
// &str 不能自动协变到 &[u8], 可以使用 as_bytes() 转换为 &[u8]
let bytes = "bors".as_bytes();
assert_eq!(b"bors", bytes);
//let s: str = "hello, world"; // 错误,str 不能直接作为类型
let s: &str = "hello, world"; // OK
// 字符串字面量是 &'static str 类型
let story = "Once upon a time...";
let ptr = story.as_ptr(); // 返回指向连续内存区域的 raw pointer:*const u8
let len = story.len(); // byte 数量
assert_eq!(19, len);
// 从 raw pointer 构建 slice
let s = unsafe {
// 由于 ptr 是 *const u8 类型,所以返回的 slice 是 &[u8] 类型
let slice = slice::from_raw_parts(ptr, len);
// 从 &[u8] 创建 &str
str::from_utf8(slice)
};
assert_eq!(s, Ok(story));
// 使用智能指针保存 str
let boxed: Box<str> = Box::from("hello");
assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant"));
let shared: Rc<str> = Rc::from("statue");
// 从 &str 创建 Vec<u8>
assert_eq!(Vec::from("123"), vec![b'1', b'2', b'3']);
// 在堆上分配字符串内存,s 拥有该对象,当 s 被 drop 时,堆内存也被释放
let s: Box<str> = "hello, world".into();
// Box<str> 实现了 Deref<Target=str>, 所以 &Box<str> 等效于 &str
greetings(&s);
其它:
b'x'
:只能存 ASCII code point,对应 u8 类型,如 104 == b’h’;b"xyz"
: byte string,只能是 ASCII 字符串,对应 &[u8; N] 类型,如 &[b’x’, b’y’,b’z’];r###"\a\b\c"###
: raw string,不对字符串内容转义,r 后面的 # 数量可变, 但只能使用连续的 # 字符;br##"\a\b\c\t\n"##
: raw byte string,只能是 ASCII 内容,类型为 &[u8, N], 不对字串转义,必须是 br 而不能是 rb;c"hello"
:C string,以 NULL 结尾的 C 字符串。cr#"hello"#
:raw C string,以 NULL 结尾的 C 原生字符串。
byte string 的类型是 &[u8; N]
,可以自动的 type coercion
到 &[u8]
:
let method = b"GET";
assert_eq!(method, &[b'G', b'E', b'T']);
// 错误的情况
assert_eq!(method, &['G', 'E', 'T']); // 类型是 &[char] 而非 &[u8]
assert_eq!(method, &[b"G", b"E", b"T"]); // 类型是 &[&[u8]] 而非 &[u8]
字符串可以包含换行和转义字符,默认左对齐, 行尾以 \
字符结尾时输出将删除换行符:
- 转义字符:
\xaF, \n, \r, \t, \\, \0, \', \", \u{0}, \u{00}, …, \u{000000}
- 不支持二进制和八进制转义字符串。
let s1 = String::from("hello,");
println!("#{:20.20}#", s1); // 字符串显示默认左对齐(数字是右对齐),显示: #hello, #
println!("{}", "a\t
b \
c d
ef
");
String 和 &str 的 Index 操作返回 &str, 但要保证 &s[i..j]
的 i..j
是有效的字符边界,否则 panic。
- 可以使用 non-panicking 版本 get();
s[i]
是禁止的,因为 String/&str 是 UTF-8 编码,返回 &u8 是无意义的;
let s = String::from("hello world");
let hello = &s[0..5]; // &str 类型
println!("{}", hello);
let s = "hello";
// println!("The first letter of s is {}", s[0]); // 错误,&str 不支持 s[i];
// 使用 as_bytes() 方法将 String/&str 转换为 &[u8], index 操作返回 u8:
let s = "hello";
assert_eq!(s.as_bytes()[0], 104);
assert_eq!(s.as_bytes()[0], b'h');
let s = "💖💖💖💖💖";
assert_eq!(s.as_bytes()[0], 240);
内存布局:
- String:三部分:指向堆内存的指针,内存的长度(bytes),内存的容量(bytes,因为是可变长度类型)。
- &str:两部分:指向 slice 内存的指针,slice 的长度(bytes)
String 和 &str 都是 严格 UTF-8 编码的
,但是对于操作系统文件名或路径,可能不是有效的
UTF-8 编码字符串,所以 Rust 引入了 std::ffi::OsStr/OsString
类型:
OsStr
: 类似于 str,是 unsized type,一般需要和 & 和 Box 使用,不可以改变;OsString
: 类似于 String,是 sized type,是 OsStr 的 Owned 类型,可以修改;它实现了Deref<target = OsStr>
,&OsString 可以使用 &OsStr 定义的所有方法;
use std::ffi::OsStr;
let os_str = OsStr::new("foo");
// OsStr 的方法:
pub fn as_encoded_bytes(&self) -> &[u8]
pub fn into_os_string(self: Box<OsStr>) -> OsString // 消耗自身
pub fn make_ascii_lowercase(&mut self)
pub fn to_os_string(&self) -> OsString
pub fn to_str(&self) -> Option<&str>
pub fn to_string_lossy(&self) -> Cow<'_, str>
std::ffi::CStr 和 std::ffi::CString
是 C 风格的 NULL 终止的字符串,主要是和 C 代码交互使用。
c"hello"
:以 NULL 结尾的 C 原生字符串;cr#"hello"#
:以 NULL 结尾的 C 原生字符串,不支持转义字符;
use std::ffi::CString;
use std::ffi::c_char;
fn main() {
let s = String::from("Hello, world!");
let cs = CString::new(s).unwrap();
let p = cs.as_ptr() as *const c_char;
println!("Address: {:?}", p);
}
2.1 str 方法 #
常用方法:
- len() : 返回 byte 数量。
- as_bytes() -> &[u8]
- as_ptr()/as_mut_ptr():返回 raw pointer: *const u8 和 *mut u8
- get()/get_mut():
安全返回子串
; - chars()/bytes():返回 char 或 byte 的迭代器;
- split_whitespace(): 返回空白字符分割的子串迭代器,连续的空白字符等效为一个;
- lines(): 返回行迭代器,行尾不包括换行;
- contains()/starts_with()/ends_with(): 检查 pattern,
pattern 支持多种类型
; - find()/rfind(): 返回匹配 pattern 的 index;
- match()/rmatch(): 返回匹配 pattern 的子串迭代器;
- trim_XX()/strip_XX(): 删除空格、删除前后缀;
- parse::<T>(): 将字符串转换为 T 类型,T 必须要实现 FromStr trait;
- replace(): 将 pattern 替换为子串;
- into_string()/to_string(): 将 &str 转换为 String;
// 返回字符串的 bytes(而非字符)长度
pub const fn len(&self) -> usize
let len = "foo".len();
assert_eq!(3, len); // 字节长度
assert_eq!("ƒoo".chars().count(), 3); // 字符数量
pub const fn is_empty(&self) -> bool
pub fn is_char_boundary(&self, index: usize) -> bool
// Finds the closest x not exceeding index where is_char_boundary(x) is true.
pub fn floor_char_boundary(&self, index: usize) -> usize
pub fn ceil_char_boundary(&self, index: usize) -> usize
#![feature(round_char_boundary)]
let s = "❤️🧡💛💚💙💜";
assert_eq!(s.len(), 26);
assert!(!s.is_char_boundary(13));
let closest = s.floor_char_boundary(13);
assert_eq!(closest, 10);
assert_eq!(&s[..closest], "❤️🧡");
// 转换为 slice 借用
pub const fn as_bytes(&self) -> &[u8]
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8]
let bytes = "bors".as_bytes();
assert_eq!(b"bors", bytes);
let mut s = String::from("Hello");
let bytes = unsafe { s.as_bytes_mut() };
assert_eq!(b"Hello", bytes);
pub const fn as_ptr(&self) -> *const u8
pub fn as_mut_ptr(&mut self) -> *mut u8
let s = "Hello";
let ptr = s.as_ptr(); // *const u8
// 安全返回一个子字符串 &str,如果不在字符串边界则返回 None
pub fn get<I>(&self, i: I) -> Option<&<I as SliceIndex<str>>::Output> where I: SliceIndex<str>
pub fn get_mut<I>( &mut self, i: I) -> Option<&mut <I as SliceIndex<str>>::Output> where I: SliceIndex<str>
let v = String::from("🗻∈🌏");
assert_eq!(Some("🗻"), v.get(0..4));
assert!(v.get(1..).is_none());
assert!(v.get(..8).is_none());
assert!(v.get(..42).is_none());
// 返回一个子字符串 &str,调用者确保传入的 index 范围是有效的。
pub unsafe fn get_unchecked<I>(&self, i: I) -> &<I as SliceIndex<str>>::Output where I: SliceIndex<str>
pub unsafe fn get_unchecked_mut<I>( &mut self, i: I ) -> &mut <I as SliceIndex<str>>::Output where I: SliceIndex<str>
// 分割字符串
pub fn split_at(&self, mid: usize) -> (&str, &str)
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)>
pub fn split_at_mut_checked( &mut self, mid: usize ) -> Option<(&mut str, &mut str)>
// 返回字符串的 char 或 byte 迭代器
pub fn chars(&self) -> Chars<'_>
pub fn char_indices(&self) -> CharIndices<'_>
pub fn bytes(&self) -> Bytes<'_>
// 返回空白字符分割的子字符串迭代器
pub fn split_whitespace(&self) -> SplitWhitespace<'_>
pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_>
let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace();
assert_eq!(Some("Mary"), iter.next());
assert_eq!(Some("had"), iter.next());
assert_eq!(Some("a"), iter.next());
assert_eq!(Some("little"), iter.next()); // 多个连续空白字符视为一个
assert_eq!(Some("lamb"), iter.next());
assert_eq!(None, iter.next());
assert_eq!("".split_whitespace().next(), None);
assert_eq!(" ".split_whitespace().next(), None);
// 返回行迭代器,如果是空行则返回空字符串,不包括行尾的换行
pub fn lines(&self) -> Lines<'_>
pub fn lines_any(&self) -> LinesAny<'_>
let text = "foo\nbar\n\r\nbaz";
// 返回的迭代器对象必须是 mut 类型,因为迭代时会修改它的内部状态
let mut lines = text.lines();
assert_eq!(Some("foo"), lines.next());
assert_eq!(Some("bar"), lines.next());
assert_eq!(Some(""), lines.next());
assert_eq!(Some("baz"), lines.next());
assert_eq!(None, lines.next());
pub fn encode_utf16(&self) -> EncodeUtf16<'_>
// 是否包含 pattern
pub fn contains<'a, P>(&'a self, pat: P) -> bool where P: Pattern<'a>
// 是否以 pattern 开始或结束
pub fn starts_with<'a, P>(&'a self, pat: P) -> bool where P: Pattern<'a>
pub fn ends_with<'a, P>(&'a self, pat: P) -> bool where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
// find 返回匹配 pattern 的 index,如果为找到则返回 None
pub fn find<'a, P>(&'a self, pat: P) -> Option<usize> where P: Pattern<'a>
pub fn rfind<'a, P>(&'a self, pat: P) -> Option<usize> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
// 拆分字符串为可迭代的子串 &str
pub fn split<'a, P>(&'a self, pat: P) -> Split<'a, P> where P: Pattern<'a>
pub fn split_inclusive<'a, P>(&'a self, pat: P) -> SplitInclusive<'a, P> where P: Pattern<'a>
pub fn split_terminator<'a, P>(&'a self, pat: P) -> SplitTerminator<'a, P> where P: Pattern<'a>
pub fn splitn<'a, P>(&'a self, n: usize, pat: P) -> SplitN<'a, P> where P: Pattern<'a>
pub fn split_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> where P: Pattern<'a>
pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
pub fn rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
pub fn rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
pub fn rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
let v: Vec<&str> = "".split('X').collect();
assert_eq!(v, [""]);
let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
assert_eq!(v, ["lion", "", "tiger", "leopard"]);
// 返回匹配 pattern 的子字符串迭代器
pub fn matches<'a, P>(&'a self, pat: P) -> Matches<'a, P> where P: Pattern<'a>
pub fn match_indices<'a, P>(&'a self, pat: P) -> MatchIndices<'a, P> where P: Pattern<'a>
pub fn rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
pub fn rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
assert_eq!(v, ["abc", "abc", "abc"]);
let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect();
assert_eq!(v, ["1", "2", "3"]);
// 删除(执行多次)start/end 两端的空格或两端匹配的 pattern
pub fn trim(&self) -> &str
pub fn trim_start(&self) -> &str
pub fn trim_end(&self) -> &str
pub fn trim_matches<'a, P>(&'a self, pat: P) -> &'a str where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: DoubleEndedSearcher<'a>
pub fn trim_start_matches<'a, P>(&'a self, pat: P) -> &'a str where P: Pattern<'a>
pub fn trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
// 删除开头的前缀,不像 trim_start_matches 那样删除多次,而是最多删除一次
pub fn strip_prefix<'a, P>(&'a self, prefix: P) -> Option<&'a str> where P: Pattern<'a>
pub fn strip_suffix<'a, P>(&'a self, suffix: P) -> Option<&'a str> where P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>
// 将字符串转换为其他类型 F,F 类型需要实现 FromStr trait。
// Rust 的基本类型都实现了该 trait。
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err> where F: FromStr
pub const fn is_ascii(&self) -> bool
pub const fn as_ascii(&self) -> Option<&[AsciiChar]>
pub fn eq_ignore_ascii_case(&self, other: &str) -> bool
pub fn make_ascii_uppercase(&mut self)
pub fn make_ascii_lowercase(&mut self)
pub const fn trim_ascii_start(&self) -> &str
pub const fn trim_ascii_end(&self) -> &str
pub const fn trim_ascii(&self) -> &str
pub fn escape_debug(&self) -> EscapeDebug<'_>
pub fn escape_default(&self) -> EscapeDefault<'_>
pub fn escape_unicode(&self) -> EscapeUnicode<'_>
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]>
pub fn replace<'a, P>(&'a self, from: P, to: &str) -> String where P: Pattern<'a>
pub fn replacen<'a, P>(&'a self, pat: P, to: &str, count: usize) -> String where P: Pattern<'a>
pub fn into_string(self: Box<str>) -> String // &str 转为 String
pub fn repeat(&self, n: usize) -> String
pub fn to_lowercase(&self) -> String
pub fn to_uppercase(&self) -> String
pub fn to_ascii_uppercase(&self) -> String
pub fn to_ascii_lowercase(&self) -> String
find/match/trim() 方法的 Pattern 参数类型:
Pattern type | Match condition |
---|---|
&str | is substring |
char | is contained in string |
&[char] | any char in slice is contained in string |
F: FnMut(char) -> bool | F returns true for a char in string |
&&str | is substring |
&String | is substring |
// &str
assert_eq!("abaaa".find("ba"), Some(1));
assert_eq!("abaaa".find("bac"), None);
// char
assert_eq!("abaaa".find('a'), Some(0));
assert_eq!("abaaa".find('b'), Some(1));
assert_eq!("abaaa".find('c'), None);
// &[char; N],注意不是 &[u8; N]
assert_eq!("ab".find(&['b', 'a']), Some(0));
assert_eq!("abaaa".find(&['a', 'z']), Some(0));
assert_eq!("abaaa".find(&['c', 'd']), None);
// &[char]
assert_eq!("ab".find(&['b', 'a'][..]), Some(0));
assert_eq!("abaaa".find(&['a', 'z'][..]), Some(0));
assert_eq!("abaaa".find(&['c', 'd'][..]), None);
// FnMut(char) -> bool
assert_eq!("abcdef_z".find(|ch| ch > 'd' && ch < 'y'), Some(4));
assert_eq!("abcddd_z".find(|ch| ch > 'd' && ch < 'y'), None);
FromStr trait
: 从 &str
来生成各种类型的值:
- Rust 基本类型,如整数、浮点数、bool、char、String、PathBuf、IpAddr、SocketAddr、 Ipv4Addr、Ipv6Addr 都实现了该 trait:
- 被泛型方法
&str.parse::<T>()
隐式调用,使用该方法时一般需要指定目标对象类型,否则编译器可能不知道该调用那个类型的FromStr trait
实现而报错;
pub trait FromStr: Sized {
type Err;
// Required method
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err> where F: FromStr
let four: u32 = "4".parse().unwrap();
assert_eq!(4, four);
let four = "4".parse::<u32>();
assert_eq!(Ok(4), four);
// Error
let nope = "j".parse::<u32>();
assert!(nope.is_err());
2.2 String #
&str 和 String 间转换:
- String -> &str: String.as_str();
- String::from(“Sunfei”) 或 “Sunface”.to_string();
创建 String:
- &str.to_string()
- &str.to_owned()
- format!()
- Array/slice/Vec 的 .concat() 和 .join()
- String::from()/String::from_utf8()
let error_message = "too many pets".to_string();
assert_eq!(format!("{}°{:02}′{:02}′′N", 24, 5, 23), "24°05′23′′N".to_string());
let bits = vec!["veni", "vidi", "vici"];
assert_eq!(bits.concat(), "venividivici");
assert_eq!(bits.join(", "), "veni, vidi, vici");
let hello = String::from("Hello, world!");
let mut hello = String::from("Hello, ");
hello.push('w');
hello.push_str("orld!");
let sparkle_heart = vec![240, 159, 146, 150];
let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();
assert_eq!("💖", sparkle_heart);
let s = "hello";
let third_character = s.chars().nth(2);
assert_eq!(third_character, Some('l'));
let noodles = "noodles".to_string();
let oodles = &noodles[1..]; // String/str 的 slice 操作返回 &str
String 类型实现了 Defref<Target = str>
, 所以 String 类型可以使用 str 定义的所有方法,在需要 &str 类型的地方可以传入 &String。
String 可以 +/+= &str
, 但是不支持 &str 之间的 +/+= 以及 &str + String 的操作:
let mut ss = String::from("abcd");
ss += " def"; // OK: String + &str
// 错误:`+` cannot be used to concatenate a `&str` with a `String`
// " def" + ss;
" def".to_owned() + &ss; // OK
let s1 = String::from("hello,");
let s2 = String::from("world!");
let s3 = s1 + &s2; // let s3 = s1.clone() +&s2;
assert_eq!(s3, "hello,world!");
//println!("{}", s1); // s1 已经在上面的 + 操作被 move, 导致继续使用 s1 出错。
String 底层是 Vec<u8>, 它的栈内存布局包括三部分,可以使用 as_ptr()/len()/capacity() 来获取它们的值:
- 指向堆连续内存的地址;
- 内存 byte 长度;
- 内存 byte 容量(因为 String 是可变长的);
let story = String::from("Once upon a time...");
// Prevent automatically dropping the String's data
let mut story = std::mem::ManuallyDrop::new(story);
let ptr = story.as_mut_ptr();
let len = story.len();
let capacity = story.capacity();
assert_eq!(19, len);
let s = unsafe { String::from_raw_parts(ptr, len, capacity) } ;
assert_eq!(String::from("Once upon a time..."), s);
String 方法:
- new()/with_capacity()
- len()/capacity()/is_empty()
- from_utf8_XX()
- into_raw_parts()/from_raw_parts()
- into_bytes()/into_boxed_str()/as_bytes()/as_str()/as_mut_str()
- push()/push_str()
- reserve()/shrink_to()/truncate()/clear()
- pop()/remove()/retaion()/insert()/insert_str()/drain()/clear()
// 空 String
pub const fn new() -> String
// 指定初始容量的空 String
pub fn with_capacity(capacity: usize) -> String
// 从 Vec<u8> 创建 String
pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>
pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String
// 从 &[u8] 创建 String
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str>
pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>
pub fn from_utf16_lossy(v: &[u16]) -> String
pub fn from_utf16le(v: &[u8]) -> Result<String, FromUtf16Error>
pub fn from_utf16le_lossy(v: &[u8]) -> String
pub fn from_utf16be(v: &[u8]) -> Result<String, FromUtf16Error>
pub fn from_utf16be_lossy(v: &[u8]) -> String
// raw pointer 互操作
pub fn into_raw_parts(self) -> (*mut u8, usize, usize)
pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize ) -> String
// 转换为 Vec<u8>, &[u8], &str
pub fn into_bytes(self) -> Vec<u8> // 消耗自身
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8>
pub fn into_boxed_str(self) -> Box<str>
pub fn as_bytes(&self) -> &[u8]
pub fn as_str(&self) -> &str
pub fn as_mut_str(&mut self) -> &mut str
// 添加或指定位置插入 char 或 &str,自动调整容量。
pub fn push(&mut self, ch: char)
pub fn push_str(&mut self, string: &str)
pub fn extend_from_within<R>(&mut self, src: R) where R: RangeBounds<usize>
pub fn insert(&mut self, idx: usize, ch: char)
pub fn insert_str(&mut self, idx: usize, string: &str)
// 返回容量和长度
pub fn capacity(&self) -> usize
pub fn len(&self) -> usize
pub fn is_empty(&self) -> bool
// 修改长度
pub fn reserve(&mut self, additional: usize)
pub fn reserve_exact(&mut self, additional: usize)
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
pub fn try_reserve_exact( &mut self, additional: usize) -> Result<(), TryReserveError>
pub fn shrink_to_fit(&mut self)
pub fn shrink_to(&mut self, min_capacity: usize)
pub fn truncate(&mut self, new_len: usize)
pub fn clear(&mut self)
// 删除 char
pub fn pop(&mut self) -> Option<char> // 为空时返回 None
pub fn remove(&mut self, idx: usize) -> char
pub fn remove_matches<P, 'a>(&'a mut self, pat: P) where P: for<'x> Pattern<'x>
// 保留 f 返回 true 的字符
pub fn retain<F>(&mut self, f: F) where F: FnMut(char) -> bool
let mut s = String::from("f_o_ob_ar");
s.retain(|c| c != '_');
assert_eq!(s, "foobar");
pub fn split_off(&mut self, at: usize) -> String
// 删除指定范围的字符,返回删除字符串的迭代器
pub fn drain<R>(&mut self, range: R) -> Drain<'_> where R: RangeBounds<usize>
let mut s = String::from("α is alpha, β is beta");
let beta_offset = s.find('β').unwrap_or(s.len());
let t: String = s.drain(..beta_offset).collect();
assert_eq!(t, "α is alpha, ");
assert_eq!(s, "β is beta");
s.drain(..);
assert_eq!(s, "");
pub fn replace_range<R>(&mut self, range: R, replace_with: &str) where R: RangeBounds<usize>
pub fn leak<'a>(self) -> &'a mut str
2.3 [u8] 方法 #
String 和 &str 的 as_bytes() 方法返回 &[u8]。
b"xxx" 的类型是 &[u8; N] 数组引用,可以自动被 unsized coercion 到 &[u8]:
impl [u8]
// 检查 [u8] 各元素是否是 ascii
pub const fn is_ascii(&self) -> bool
pub const fn as_ascii(&self) -> Option<&[AsciiChar]>
pub const unsafe fn as_ascii_unchecked(&self) -> &[AsciiChar]
pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool
pub fn make_ascii_uppercase(&mut self)
pub fn make_ascii_lowercase(&mut self)
pub fn escape_ascii(&self) -> EscapeAscii<'_>
let s = b"0\t\r\n'\"\\\x9d";
let escaped = s.escape_ascii().to_string();
assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
pub const fn trim_ascii_start(&self) -> &[u8]
pub const fn trim_ascii_end(&self) -> &[u8]
pub const fn trim_ascii(&self) -> &[u8]
#![feature(byte_slice_trim_ascii)]
assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
assert_eq!(b" ".trim_ascii_start(), b"");
assert_eq!(b"".trim_ascii_start(), b"");
[u8] 的 as_ascii() 返回 [AsciiChar] 类型:
impl [AsciiChar]
pub const fn as_str(&self) -> &str
pub const fn as_bytes(&self) -> &[u8]
3 array #
array 是同类型元素, 固定长度,在栈上分配的连续内存空间,用 [T; N]
表示,
N 必须是编译时常量表达式。
创建 array:
// 声明一个有 5 个 i32 整数的数组
let numbers: [i32; 5] = [1, 2, 3, 4, 5];
// 声明一个有 5 个元素都是 0 的数组,表达式右侧 [Value; N] 的 Value 类型必须实现 Copy
let zeroes: [i32; 5] = [0; 5];
let mut values: [i32; 3] = [10, 20, 30];
values[1] = 25;
println!("values: {:?}", values);
println!("The array has {} elements.", values.len());
Rust 数组和集合的元素索引都从 0 开始, index 必须 < len(), 否则 panic。
a[start..end] ~返回一个 dynamic size 的 slice 类型 [T],故一般使用 ~&a[start..end]
。slice 操作不需要拷贝堆内存, 也不拥有任何数据,而只是共享借用 array/Vec 中的数据。
let arr = [1, 2, 3, 4, 5];
// 创建一个包含整个数组的 slice
let slice_whole = &arr[..];
// 创建一个包含数组中一部分元素的 slice
let slice_part = &arr[1..4];
let a = [1, 2, 3, 4, 5];
// a[1..3] 返回的类型为 [i32], &a[1..3] 返回的类型为 &[i32]
let slice = &a[1..3];
// &[i32] 可以直接和 &[i32; 2] 类型比较
assert_eq!(slice, &[2, 3]);
// 一个接受切片作为参数的函数
fn sum(slice: &[i32]) -> i32 {
let mut total = 0;
for i in slice {
total += i;
}
total
}
fn main() {
let arr = [1, 2, 3, 4, 5];
let result = sum(&arr[1..4]); // 只计算数组一部分的和
println!("The sum of the part of the array is: {}", result);
}
array 支持 for-in 迭代,结果为数组元素 T。slice 操作 &a[m..n], 结果为切片引用 &[T],它的迭代结果为 &T;
fn main() {
let mut numbers: [i32; 5] = [1, 2, 3, 4, 5];
// numbers.iter()/numbers.iter_mut()/numbers.into_iter()
for number in numbers {
println!("number: {}", number);
}
}
Rust 不允许 Array/Vec/HashMap/HashSet 中的元素被 partial move 出来(全部 move 出来是 OK 的,如通过迭代),所以如果 array 元素不支持 Copy,则 index 操作后转移会失败:
- 允许 struct/tuple/union 中的 field 被部分 move,只不过被 move 的成员不能再读取;
- & 和 &mut 借用的对象如果没有实现 Copy,都不允许 move 出来;
解决办法:
- 使用 std::mem::replace() 来用同类型对象替换(返回元素 T);
- 或者使用 slice pattern match 来提取;
- 或者使用 std::mem::take() 来返回值(将原始值设置为缺省值);
// 全部 move 出来,OK!
fn move_away(_: String)
let [john, roa] = ["John".to_string(), "Roa".to_string()];
move_away(john);
move_away(roa);
// 部分 move 失败!
struct Buffer<T> {
buf: Vec<T>
}
impl<T> Buffer<T> {
fn replace_index(&mut self, i: usize, v: T) -> T {
// error: cannot move out of dereference of `&mut`-pointer
let t = self.buf[i];
self.buf[i] = v;
t
}
}
// std::mem::replace 对 &mut 对象替换, 返回替换前的对象
impl<T> Buffer<T> {
fn replace_index(&mut self, i: usize, v: T) -> T {
std::mem::replace(&mut self.buf[i], v)
}
}
另一种常见的解法是在 Array/Vec 中保存 Option<T>,如 Vec<Option<T>>, 这样如果要删除某个元素,将它 设置为 None 即可
。
如果 array 元素实现了如下 trait,则 array 也实现了对应 trait:
- Copy,Clone
- Debug(array
没有实现
Display) - IntoIterator (implemented for [T; N], &[T; N] and &mut [T; N])
- PartialEq, PartialOrd, Eq, Ord
- Hash
- AsRef, AsMut
- Borrow, BorrowMut
println!("numbers: {:?}", numbers);
println!("zeroes: {:?}", zeroes);
array [T; N] 可以被隐式 type coerce 到 slice 类型 [T], 也即 &[T; N] 可以被隐式自动转换为 &[T],所以 array 可以调用 slice 的方法
;
- array 并没有实现 Deref trait,所以上面的自动转换不是 Deref 的行为;d按时 Vec<T> 实现了 Deref<Target=[T]>。
- 但是反过来 [T] 是 dynamic size, 不能反向 coerce 到 array。
// 左边是类型, 右边是初始化表达式!
let mut array: [i32; 3] = [0; 3];
// coercing an array to a slice
let str_slice: &[&str] = &["one", "two", "three"];
// numbers 是 &[i32; 3] 类型,函数传参时被自动转换为 &[i32] 类型
let numbers = &[0, 1, 2];
print_type_of(&numbers);
// 数组 [i32; 3] 可以被 type coerce 到 [T], 所以 &[i32; 3] 可以被赋值给 &[i32]
let numbers: &[i32] = &[0, 1, 2];
print_type_of(&numbers);
// number 虽然前面没有加 &, 但它本身是 &[i32] 类型, 所以迭代后元素 n 是 &32 类型.
for n in numbers {
print_type_of(&n);
}
// 传入的 v 值是 &T 类型,返回 T 的类型
fn print_type_of<T>(v: &T) -> String {
format!("{}", std::any::type_name_of_val(v))
}
// 切片引用支持 index 操作,返回元素本身。如果要 move,则必须实现 Copy, 否则报错。
print_type_of(&numbers[0]); // i32
// A heap-allocated array, coerced to a slice
let boxed_array: Box<[i32]> = Box::new([1, 2, 3]);
使用 slice.try_into().unwrap()
或 <ArrayType>::try_from(slice).unwrap()
来在相同长度的 slice 和 array 之间转换:
let mut bytes: [u8; 3] = [1, 0, 2];
let bytes_head: [u8; 2] = <[u8; 2]>::try_from(&mut bytes[0..2]).unwrap();
assert_eq!(1, u16::from_le_bytes(bytes_head));
let bytes_tail: [u8; 2] = (&mut bytes[1..3]).try_into().unwrap();
assert_eq!(512, u16::from_le_bytes(bytes_tail));
array 方法:
- array 转为 slice:as_slice()/as_mut_slice();
- 获得各元素引用的数组:each_ref/each_mut();
impl<T, const N: usize> [T; N]
pub fn map<F, U>(self, f: F) -> [U; N] where F: FnMut(T) -> U
pub fn try_map<F, R>( self, f: F, ) -> ::TryType
where F: FnMut(T) -> R, R: Try, <R as Try>::Residual: Residual<[<R as Try>::Output; N]>
pub const fn as_slice(&self) -> &[T]
pub fn as_mut_slice(&mut self) -> &mut [T]
pub fn each_ref(&self) -> [&T; N]
pub fn each_mut(&mut self) -> [&mut T; N]
pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T])
pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T])
pub fn rsplit_array_ref<const M: usize>(&self) -> (&[T], &[T; M])
pub fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T], &mut [T; M])
impl<T, const N: usize> [MaybeUninit<T>; N]
pub const fn transpose(self) -> MaybeUninit<[T; N]>
// u8 数组
impl<const N: usize> [u8; N]
pub const fn as_ascii(&self) -> Option<&[AsciiChar; N]>
pub const unsafe fn as_ascii_unchecked(&self) -> &[AsciiChar; N]
// array 实现的 trait
impl<T, const N: usize> AsMut<[T]> for [T; N]
impl<T, const N: usize> AsRef<[T]> for [T; N]
impl<T, const N: usize> Borrow<[T]> for [T; N]
impl<T, const N: usize> BorrowMut<[T]> for [T; N]
// array 转为 Vec
impl<T, const N: usize> From<&[T; N]> for Vec<T> where T: Clone
impl<T, const N: usize> From<&mut [T; N]> for Vec<T> where T: Clone
// array 转为容器类型
impl<K, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> where K: Ord
impl<K, V, const N: usize> From<[(K, V); N]> for HashMap<K, V, RandomState> where K: Eq + Hash
impl<T, const N: usize> From<[T; N]> for BTreeSet<T> where T: Ord
impl<T, const N: usize> From<[T; N]> for BinaryHeap<T> where T: Ord
impl<T, const N: usize> From<[T; N]> for HashSet<T, RandomState> where T: Eq + Hash
impl<T, const N: usize> From<[T; N]> for LinkedList<T>
impl<T, const N: usize> From<[T; N]> for Vec<T>
impl<T, const N: usize> From<[T; N]> for VecDeque<T>
// array 转为智能指针
impl<T, const N: usize> From<[T; N]> for Arc<[T]>
impl<T, const N: usize> From<[T; N]> for Box<[T]>
impl<T, const N: usize> From<[T; N]> for Rc<[T]>
impl<'a, T, const N: usize> From<&'a [T; N]> for Cow<'a, [T]> where T: Clone
impl From<[u16; 8]> for IpAddr
impl From<[u16; 8]> for Ipv6Addr
impl From<[u8; 16]> for IpAddr
impl From<[u8; 16]> for Ipv6Addr
impl From<[u8; 4]> for IpAddr
impl From<[u8; 4]> for Ipv4Addr
impl<T> From<(T,)> for [T; 1]
impl<T> From<(T, T, T, T, T, T, T, T, T, T, T, T)> for [T; 12]
impl<T> From<[T; 1]> for (T,)
impl<T> From<[T; 9]> for (T, T, T, T, T, T, T, T, T)
4 slice #
slice 代表一块连续的内存区域,用 [T] 表示,它是编译时大小未知的类型。作为变量/函数输入/输出参数类型来使用时, 一般使用编译时固定大小的 &[T] 或 Box<[T]> 类型:
- 虽然编译时大小未知,但是 .len() 返回 slice 的元素数量;
- &[T] 是大小固定为 2 usize 的 fat pointer,包含指向内存区域的指针和 bytes 数量;
let pointer_size = std::mem::size_of::<&u8>();
assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>());
assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>());
// slice 的智能指针也是 2 usize
assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
// 注意:Box<T>/Rc<T> 的栈大小,取决于 T 类型
// 1. 基本类型,如 i32,Box<i32> 占用 1 usize 大小,表示内存地址
// 2. slice 类型,如 Box<[i32]> 占用 2 usize 大小,分别是内存地址和 byte 数量;
// 3. dyn trait 类型,如 Box<dyn std::error::Error> 占用 3 usize 大小;
创建 slice &[T]:
- array/Vec/String/&str 的 range index 操作返回 [T], 如 &v[0..2],&v[..] 等;
- Vec[T] 实现了 Deref<Target=[T]>,&Vec<T> 可以被隐式转换为 &[T],在需要 &[T] 类型的地方可以传入&Vec<T> 类型,Vec 对象也可以调用 slice [T] 的方法;
- &vec 返回 &Vec<i32> 类型,而 &vec[n..m] 返回 &[i32];
- array [T; N] 可以被 type coercing 到 [T], 所以 &[T; N] 可以被隐式转换为 &[T],这样 array 对象也可以调用 slice [T] 的方法;
// slicing a Vec
let vec = vec![1, 2, 3];
let int_slice = &vec[..]; // &vec 返回的是 &Vec<i32> 类型而非 &[i32]
// 由于 Vec<T> 实现了 Deref<Target=[T]>,所以 &Vec<i32> 可以被转换为 &[i32] 类型
let int_slice: &[i32] = &vec;
// coercing an array to a slice
let str_slice: &[&str] = &["one", "two", "three"];
let mut x = [1, 2, 3];
let x = &mut x[..];
x[1] = 7;
assert_eq!(x, &[1, 7, 3]);
// 由于数组 [i32; 3] 可以被 coerce 到 unsize 的 [T], 所以 &[i32; 3] 可以被赋值给 &[i32]
let numbers: &[i32] = &[0, 1, 2];
print_type_of(&numbers);
for n in numbers {
print_type_of(&n); // n 的类型是 &i32
}
print_type_of(&numbers[0]); // i32,切片引用的支持 index 操作,返回元素本身
fn read_slice(slice: &[usize]) {}
let v = vec![0, 1];
read_slice(&v); // Deref 自动转换
let u: &[usize] = &v; // Deref 自动转换
let u: &[_] = &v; // 自动推断 slice 类型
s[i] 返回的 s 的元素值,而非它的引用,所以支持将 x[i] 作为 左值
:
let mut x = [1, 2, 3];
let x = &mut x[..];
x[1] = 7;
for-in 迭代 &[T] 时返回 &T 元素,同理 &mut [T] 时返回 &mut T 元素:
// &[0, 1, 2] 的类型是 &[i32; 3] 被 rust 自动转换为 &[i32]
let numbers: &[i32] = &[0, 1, 2];
for n in numbers { // n 是 &i32 类型
println!("{n} is a number!");
}
let mut scores: &mut [i32] = &mut [7, 8, 9];
for score in scores { // score 是 &mut i32 类型.
*score += 1;
}
对 array/slice 进行 index 操作时,如果超过了 length,则会 panic。解决办法是使用安全的 .get() 方法,它返回一个 Option,get() 方法的参数类型是 SliceIndex<[T]>, Range<usize>/RangeFull/RangeFrom<usize> 等均实现了该 trait:
for i in 0..xs.len() + 1 {
match xs.get(i) {
Some(xval) => println!("{}: {}", i, xval),
None => println!("Slow down! {} is too far!", i),
}
}
let v = [10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));
数组 slice 的 flatten:
impl<T, const N: usize> [[T; N]]
pub const fn flatten(&self) -> &[T]
#![feature(slice_flatten)]
assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
assert_eq!(
[[1, 2, 3], [4, 5, 6]].flatten(),
[[1, 2], [3, 4], [5, 6]].flatten(),
);
let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
assert!(slice_of_empty_arrays.flatten().is_empty());
let empty_slice_of_arrays: &[[u32; 10]] = &[];
assert!(empty_slice_of_arrays.flatten().is_empty());
slice [T] 方法:由于 array 可以被 type coerse 到 [T], 而 Vec<T> 实现了 Deref<Target=[T]>, 所以 array/Vec 也可以调用 slice 方法。
- 不能直接迭代 slice, 而是调用它的 iter() 或 iter_mut() 方法返回的迭代器;
- concat()/join(&sep) 方法用于数组的数组,将数组的元素打平或加入新的分隔符;
- assert_eq!([[1,2], [3,4]].concat(), vec![1,2,3,4]);
- assert_eq!([[1,2], [3,4]].join(&0), vec![1,2,0,3,4]);
- chunks() 返回指定长度的 &[T] 的迭代器;
impl<T> [T]
// 返回元素数量
pub const fn len(&self) -> usize
pub const fn is_empty(&self) -> bool
// slice 有可能为空,所以 first/last 都返回 Option
pub const fn first(&self) -> Option<&T>
pub fn first_mut(&mut self) -> Option<&mut T>
pub const fn last(&self) -> Option<&T>
pub fn last_mut(&mut self) -> Option<&mut T>
// 拆分 slice
pub const fn split_first(&self) -> Option<(&T, &[T])>
pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])>
pub const fn split_last(&self) -> Option<(&T, &[T])>
pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])>
// x 是 &[i32; 3] 类型,但是可以被 type coerce 到 &[i32] 类型,所以可以调用 slice [T] 的方法。
let x = &[0, 1, 2];
if let Some((first, elements)) = x.split_first() {
assert_eq!(first, &0);
assert_eq!(elements, &[1, 2]);
}
// 返回第一个 N 个元素的数组,如果元素少于 N 则返回 None
//
// 由于数组长度必须是编译时常量,所以 N 是通过常量泛型参数传入的。
pub const fn first_chunk<const N: usize>(&self) -> Option<&[T; N]>
pub fn first_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]>
pub fn last_chunk<const N: usize>(&self) -> Option<&[T; N]>
pub fn last_chunk_mut<const N: usize>(&mut self) -> Option<&mut [T; N]>
let u = [10, 40, 30];
assert_eq!(Some(&[10, 40]), u.first_chunk::<2>()); // 指定泛型常量的值为 2
let v: &[i32] = &[10];
assert_eq!(None, v.first_chunk::<2>());
let w: &[i32] = &[];
assert_eq!(Some(&[]), w.first_chunk::<0>());
// 返回第一个或最后一个 chunk 数组和剩下的 slice,如果元素少于 N 则返回 None
pub const fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])>
pub fn split_first_chunk_mut<const N: usize>( &mut self ) -> Option<(&mut [T; N], &mut [T])>
pub const fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])>
pub fn split_last_chunk_mut<const N: usize>( &mut self ) -> Option<(&mut [T], &mut [T; N])>
let x = &[0, 1, 2];
if let Some((first, elements)) = x.split_first_chunk::<2>() {
assert_eq!(first, &[0, 1]);
assert_eq!(elements, &[2]);
}
assert_eq!(None, x.split_first_chunk::<4>());
// 安全的返回 slice 中元素(s[index] 当 index 不在范围时会 panic )
pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output> where I: SliceIndex<[T]>
pub fn get_mut<I>( &mut self, index: I ) -> Option<&mut <I as SliceIndex<[T]>>::Output> where I: SliceIndex<[T]>
pub unsafe fn get_unchecked<I>( &self, index: I ) -> &<I as SliceIndex<[T]>>::Output where I: SliceIndex<[T]>
pub unsafe fn get_unchecked_mut<I>( &mut self, index: I ) -> &mut <I as SliceIndex<[T]>>::Output where I: SliceIndex<[T]>
let v = [10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));
// 创建裸指针
pub const fn as_ptr(&self) -> *const T
pub const fn as_mut_ptr(&mut self) -> *mut T
let x = &[1, 2, 4];
let x_ptr = x.as_ptr();
unsafe {
for i in 0..x.len() {
assert_eq!(x.get_unchecked(i), &*x_ptr.add(i));
}
}
let x = &mut [1, 2, 4];
let x_ptr = x.as_mut_ptr();
unsafe {
for i in 0..x.len() {
*x_ptr.add(i) += 2;
}
}
assert_eq!(x, &[3, 4, 6]);
// 返回包含所有元素的原始指针的区间(因为 slice 内存空间连续)
pub const fn as_ptr_range(&self) -> Range<*const T>
pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T>
let a = [1, 2, 3];
let x = &a[1] as *const _;
let y = &5 as *const _;
assert!(a.as_ptr_range().contains(&x));
assert!(!a.as_ptr_range().contains(&y));
// 交换两个位置的值
pub fn swap(&mut self, a: usize, b: usize)
pub unsafe fn swap_unchecked(&mut self, a: usize, b: usize)
let mut v = ["a", "b", "c", "d", "e"];
v.swap(2, 4);
assert!(v == ["a", "b", "e", "d", "c"]);
// 反转 slice 元素
pub fn reverse(&mut self)
// 返回可迭代对象
pub fn iter(&self) -> Iter<'_, T>
pub fn iter_mut(&mut self) -> IterMut<'_, T>
// 可重叠,如果元素数量比窗口小,则返回 None
pub fn windows(&self, size: usize) -> Windows<'_, T>
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.windows(3);
assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']);
assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']);
assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']);
assert!(iter.next().is_none());
let slice = ['f', 'o', 'o'];
let mut iter = slice.windows(4);
assert!(iter.next().is_none());
// 不重叠的分组迭代,每次迭代返回一个切片 &[T]
pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T>
pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T>
pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T>
pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T>
pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]]
pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T>
pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T>
pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T>
pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T>
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 slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.chunks_exact(2);
assert_eq!(iter.next().unwrap(), &['l', 'o']);
assert_eq!(iter.next().unwrap(), &['r', 'e']);
// 如果最后一波元素少与数量,则返回 None,可以使用 remainer() 方法来获取它们
assert!(iter.next().is_none());
assert_eq!(iter.remainder(), &['m']);
// 分为 N 个元素数组的 slice 和最后剩下的元素 slice。
// 注意:N 是泛型参数,编译器可以自动推导。
pub const fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T])
pub const fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]])
pub const unsafe fn as_chunks_unchecked_mut<const N: usize>( &mut self ) -> &mut [[T; N]]
pub const fn as_chunks_mut<const N: usize>( &mut self ) -> (&mut [[T; N]], &mut [T])
pub const fn as_rchunks_mut<const N: usize>( &mut self) -> (&mut [T], &mut [[T; N]])
#![feature(slice_as_chunks)]
let slice = ['l', 'o', 'r', 'e', 'm'];
let (chunks, remainder) = slice.as_chunks();
assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
assert_eq!(remainder, &['m']);
#![feature(slice_as_chunks)]
let slice = ['R', 'u', 's', 't'];
let (chunks, []) = slice.as_chunks::<2>() else { // 使用 let-else 来匹配剩下元素的列表
panic!("slice didn't have even length")
};
assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
// chunks_exact 的泛型常量版本,即数组的长度是通过泛型常量参数来指定的,编译器可以自动推导。
pub fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N>
pub fn array_chunks_mut<const N: usize>(&mut self) -> ArrayChunksMut<'_, T, N>
pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N>
#![feature(array_chunks)]
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.array_chunks();
assert_eq!(iter.next().unwrap(), &['l', 'o']);
assert_eq!(iter.next().unwrap(), &['r', 'e']);
assert!(iter.next().is_none());
assert_eq!(iter.remainder(), &['m']);
//使用 pred 来分割 slice(不重合的分割),pred 返回 true 时对应连续的元素属于一个 slice
pub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F> where F: FnMut(&T, &T) -> bool
pub fn chunk_by_mut<F>(&mut self, pred: F) -> ChunkByMut<'_, T, F> where F: FnMut(&T, &T) -> pub
let slice = &[1, 1, 1, 3, 3, 2, 2, 2];
let mut iter = slice.chunk_by(|a, b| a == b);
assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
assert_eq!(iter.next(), Some(&[3, 3][..]));
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter.next(), None);
// 在指定的 index 位置拆分 slice
bool const fn split_at(&self, mid: usize) -> (&[T], &[T])
pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T])
pub const unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T])
pub unsafe fn split_at_mut_unchecked( &mut self, mid: usize ) -> (&mut [T], &mut [T])
pub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])>
pub fn split_at_mut_checked( &mut self, mid: usize ) -> Option<(&mut [T], &mut [T])>
let v = [1, 2, 3, 4, 5, 6];
{
let (left, right) = v.split_at(0);
assert_eq!(left, []);
assert_eq!(right, [1, 2, 3, 4, 5, 6]);
}
{
let (left, right) = v.split_at(2);
assert_eq!(left, [1, 2]);
assert_eq!(right, [3, 4, 5, 6]);
}
{
let (left, right) = v.split_at(6);
assert_eq!(left, [1, 2, 3, 4, 5, 6]);
assert_eq!(right, []);
}
// 使用指定的 pred 分割 slice,可能会导致空 slice
pub fn split<F>(&self, pred: F) -> Split<'_, T, F> where F: FnMut(&T) -> bool
pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<'_, T, F> where F: FnMut(&T) -> bool
pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F> where F: FnMut(&T) -> bool
pub fn split_inclusive_mut<F>(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F> where F: FnMut(&T) -> bool
pub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F> where F: FnMut(&T) -> bool
pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<'_, T, F> where F: FnMut(&T) -> bool
pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F> where F: FnMut(&T) -> bool
pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<'_, T, F> where F: FnMut(&T) -> bool
pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F> where F: FnMut(&T) -> bool
pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<'_, T, F> where F: FnMut(&T) -> bool
pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])> where F: FnMut(&T) -> bool
pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])> where F: FnMut(&T) -> bool
let slice = [10, 6, 33, 20];
let mut iter = slice.split(|num| num % 3 == 0);
assert_eq!(iter.next().unwrap(), &[10]);
assert_eq!(iter.next().unwrap(), &[]);
assert_eq!(iter.next().unwrap(), &[20]);
assert!(iter.next().is_none());
let slice = [10, 40, 33];
let mut iter = slice.split(|num| num % 3 == 0);
assert_eq!(iter.next().unwrap(), &[10, 40]);
assert_eq!(iter.next().unwrap(), &[]); // 结尾空 slice
assert!(iter.next().is_none());
let slice = [10, 40, 33, 20];
let mut iter = slice.split_inclusive(|num| num % 3 == 0);
assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
assert_eq!(iter.next().unwrap(), &[20]);
assert!(iter.next().is_none());
let v = [10, 40, 30, 20, 60, 50];
for group in v.splitn(2, |num| *num % 3 == 0) {
println!("{group:?}");
}
#![feature(slice_split_once)]
let s = [1, 2, 3, 2, 4];
assert_eq!(s.split_once(|&x| x == 2), Some((
&[1][..],
&[3, 2, 4][..]
)));
assert_eq!(s.split_once(|&x| x == 0), None);
// 是否包含引用值
pub fn contains(&self, x: &T) -> bool where T: PartialEq
let v = [10, 40, 30];
assert!(v.contains(&30));
assert!(!v.contains(&50));
// 是否以指定 slice 开始或结尾
pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq
pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq
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]));
// 删除开始或结尾的 slice
pub fn strip_prefix<P>(&self, prefix: &P) -> Option<&[T]> where P: SlicePattern<Item = T> + ?Sized, T: PartialEq
pub fn strip_suffix<P>(&self, suffix: &P) -> Option<&[T]> where P: SlicePattern<Item = T> + ?Sized, T: PartialEq
let v = &[10, 40, 30];
assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
assert_eq!(v.strip_prefix(&[50]), None);
assert_eq!(v.strip_prefix(&[10, 50]), None);
let prefix : &str = "he";
assert_eq!(b"hello".strip_prefix(prefix.as_bytes()), Some(b"llo".as_ref()));
pub fn binary_search(&self, x: &T) -> Result<usize, usize> where T: Ord
pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize> where F: FnMut(&'a T) -> Ordering
pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B,f:F) -> Result<usize, usize> where F: FnMut(&'a T) -> B,B: Ord
// 对 slice 进行排序,unstable 表示不保证重复元素的顺序
pub fn sort_unstable(&mut self) where T: Ord
pub fn sort_unstable_by<F>(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering
pub fn sort_unstable_by_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord
pub fn select_nth_unstable( &mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) where T: Ord
pub fn select_nth_unstable_by<F>( &mut self, index: usize, compare: F) -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T, &T) -> Ordering
pub fn select_nth_unstable_by_key<K, F>( &mut self, index: usize, f: F ) -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T) -> K, K: Ord
let mut v = [-5, 4, 1, -3, 2];
v.sort_unstable();
assert!(v == [-5, -3, 1, 2, 4]);
// 返回两个 slice,分别是没有重复的元素,重复的元素(没有顺序)
pub fn partition_dedup(&mut self) -> (&mut [T], &mut [T]) where T: PartialEq
pub fn partition_dedup_by<F>(&mut self, same_bucket: F) -> (&mut [T], &mut [T]) where F: FnMut(&mut T, &mut T) -> bool
pub fn partition_dedup_by_key<K, F>(&mut self, key: F) -> (&mut [T], &mut [T]) where F: FnMut(&mut T) -> K, K: PartialEq
#![feature(slice_partition_dedup)]
let mut slice = [1, 2, 2, 3, 3, 2, 1, 1];
let (dedup, duplicates) = slice.partition_dedup();
assert_eq!(dedup, [1, 2, 3, 2, 1]);
assert_eq!(duplicates, [2, 3, 1]);
// 向左轮转两个元素
pub fn rotate_left(&mut self, mid: usize)
pub fn rotate_right(&mut self, k: usize)
let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
a.rotate_left(2);
assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
// 使用指定值填充整个 slice
pub fn fill(&mut self, value: T) where T: Clone
// 使用指定函数返回值填充整个 slice
pub fn fill_with<F>(&mut self, f: F) where F: FnMut() -> T
let mut buf = vec![0; 10];
buf.fill(1);
assert_eq!(buf, vec![1; 10]);
// 从 src clone 元素到 self,src 和 self 的长度必须一致,否则 panic
pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone
pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy
let src = [1, 2, 3, 4];
let mut dst = [0, 0];
dst.clone_from_slice(&src[2..]); // 长度必须一致
assert_eq!(src, [1, 2, 3, 4]);
assert_eq!(dst, [3, 4]);
// 使用 memmove 将 src 的范围元素拷贝到 dest 开始的位置,两者可以有重复
pub fn copy_within<R>(&mut self, src: R, dest: usize) where R: RangeBounds<usize>, T: Copy
let mut bytes = *b"Hello, World!";
bytes.copy_within(1..5, 8);
assert_eq!(&bytes, b"Hello, Wello!");
// 交换内容,两个 slice 的长度必须一致
pub fn swap_with_slice(&mut self, other: &mut [T])
let mut slice1 = [0, 0];
let mut slice2 = [1, 2, 3, 4];
slice1.swap_with_slice(&mut slice2[2..]);
assert_eq!(slice1, [3, 4]);
assert_eq!(slice2, [1, 2, 0, 0]);
pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T])
pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T])
pub fn is_sorted(&self) -> bool where T: PartialOrd
pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool where F: FnMut(&'a T, &'a T) -> bool
pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool where F: FnMut(&'a T) -> K, K: PartialOrd
// 返回 pred 返回 true 的 index
pub fn partition_point<P>(&self, pred: P) -> usize where P: FnMut(&T) -> bool
let v = [1, 2, 3, 3, 5, 6, 7];
let i = v.partition_point(|&x| x < 5);
assert_eq!(i, 4);
assert!(v[..i].iter().all(|&x| x < 5));
assert!(v[i..].iter().all(|&x| !(x < 5)));
let a = [2, 4, 8];
assert_eq!(a.partition_point(|x| x < &100), a.len());
let a: [i32; 0] = [];
assert_eq!(a.partition_point(|x| x < &100), 0);
// 从 self 拿出 range 元素并返回,self 是剩下的元素
pub fn take<R, 'a>(self: &mut &'a [T], range: R) -> Option<&'a [T]> where R: OneSidedRange<usize>
pub fn take_mut<R, 'a>(self: &mut &'a mut [T], range: R) -> Option<&'a mut [T]> where R: OneSidedRange<usize>
pub fn take_first<'a>(self: &mut &'a [T]) -> Option<&'a T>
pub fn take_first_mut<'a>(self: &mut &'a mut [T]) -> Option<&'a mut T>
pub fn take_last<'a>(self: &mut &'a [T]) -> Option<&'a T>
pub fn take_last_mut<'a>(self: &mut &'a mut [T]) -> Option<&'a mut T>
#![feature(slice_take)]
let mut slice: &[_] = &['a', 'b', 'c', 'd'];
let mut first_three = slice.take(..3).unwrap();
assert_eq!(slice, &['d']);
assert_eq!(first_three, &['a', 'b', 'c']);
#![feature(slice_take)]
let mut slice: &[_] = &['a', 'b', 'c', 'd'];
let mut tail = slice.take(2..).unwrap();
assert_eq!(slice, &['a', 'b']);
assert_eq!(tail, &['c', 'd']);
#![feature(slice_take)]
let mut slice: &[_] = &['a', 'b', 'c'];
let first = slice.take_first().unwrap();
assert_eq!(slice, &['b', 'c']);
assert_eq!(first, &'a');
// 返回多个元素的呃引用,各元素的 index 由传入的 indices 指定。
pub unsafe fn get_many_unchecked_mut<const N: usize>( &mut self, indices: [usize; N] ) -> [&mut T; N]
pub fn get_many_mut<const N: usize>( &mut self, indices: [usize; N] ) -> Result<[&mut T; N], GetManyMutError<N>>
#![feature(get_many_mut)]
let v = &mut [1, 2, 3];
if let Ok([a, b]) = v.get_many_mut([0, 2]) {
*a = 413;
*b = 612;
}
assert_eq!(v, &[413, 2, 612]);
// 其它 [T] 方法
impl<T> [T]
pub fn sort(&mut self) where T: Ord
pub fn sort_by<F>(&mut self, compare: F) where F: FnMut(&T, &T) -> Ordering
pub fn sort_by_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord
pub fn sort_by_cached_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord
let mut v = [-5, 4, 1, -3, 2];
v.sort();
assert!(v == [-5, -3, 1, 2, 4]);
let mut v = [-5i32, 4, 1, -3, 2];
v.sort_by_key(|k| k.abs());
assert!(v == [1, 2, -3, 4, -5]);
// 从 slice clone 生成 Vec,两个对象后续是无关的。
pub fn to_vec(&self) -> Vec<T> where T: Clone
pub fn to_vec_in<A>(&self, alloc: A) -> Vec<T, A> where A: Allocator, T: Clone
let s = [10, 40, 30];
let x = s.to_vec();
// 消耗 self
pub fn into_vec<A>(self: Box<[T], A>) -> Vec<T, A> where A: Allocator
let s: Box<[i32]> = Box::new([10, 40, 30]);
let x = s.into_vec();
assert_eq!(x, vec![10, 40, 30]); // s 不能再使用
pub fn repeat(&self, n: usize) -> Vec<T> where T: Copy
assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
// 将 slice 打平为一个值
pub fn concat<Item>(&self) -> <[T] as Concat<Item>>::Output where [T]: Concat<Item>, Item: ?Sized
assert_eq!(["hello", "world"].concat(), "helloworld");
assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
// 使用指定分隔符打平 slice
pub fn join<Separator>( &self, sep: Separator) -> <[T] as Join<Separator>>::Output where [T]: Join<Separator>
assert_eq!(["hello", "world"].join(" "), "hello world");
assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
5 tuple #
tuple 固定大小,可以保存不同数据类型,用 (T1, T2, T3) 表示。可以使用 pattern match 进行析构, 非常适合于存储和传递一组异构数据。
fn main() {
let _t0: (u8,i16) = (0, -1);
let _t1: (u8, (i16, u32)) = (0, (-1, 1));
let t: (u8, u16, i64, &str, String) =
(1u8, 2u16, 3i64, "hello", String::from(", world"));
println!("Success!");
}
// 函数接受一个元组作为参数,并返回一个元组
fn swap(tup: (i32, f64)) -> (f64, i32) {
(tup.1, tup.0)
}
let input_tup = (123, 4.56);
let output_tup = swap(input_tup);
// 创建一个嵌套的元组结构
let nested_tup = (1, (2, 3), 4);
// 解构元组
let (a, (b, c), d) = nested_tup;
// 创建一个零元素的元组,也称为单元类型(unit type),只有一个唯一的类型和值: ();
let unit = ();
单个元素类型时,元素后需要加逗号,如 (T,) ,以免和函数参数混淆。多个元素时,最后一个元素后的逗号是可选。
tuple 拥有各元素对象, 和 struct 一样, 允许部分元素被 move 走, 但是后续不能再访问已经 move 的元素:
- array/Vec/slice 等集合不允许元素被 move 走,具体参考: [BROKEN LINK: rust-lang/rust-lang-borrow.pre-processed.org]
析构 tuple: enum 是在枚举 variant 值外部而非内部类匹配 & 或 &mut 的,tuple 也是类似。
let x: &Option<i32> = &Some(3);
// OK: y 的类型是 &i32
if let Some(y) = x {}
// OK: 在 variant 外指定 &,y 的类型是 i32
if let &Some(y) = x {}
// ERROR: 不能在 variant 内指定 &,expected `i32`, found `&_`
if let Some(&y) = x {}
let (a, b ) = &(1, 2); // a 和 b 都是 &i32 类型
let &(c, d ) = &(1, 2); // c 和 d 都是 i32 类型
let (&c, d ) = &(1, 2); // 错误
let (ref c, d ) = &(1, 2); // OK
// 另一个例子
enum MyEnum {
A { name: String, x: u8 },
B { name: String },
}
fn a_to_b(e: &mut MyEnum) {
// name 和 x 都是析构后的变量名,可以在后面的 block 中使用。name 是 &mut String 类型。
if let MyEnum::A { name, x: 0, } = e {
*e = MyEnum::B {
name: std::mem::take(name), // take 参数类型是 &mut T, 而 name 类型是 &mut String 故满足
}
}
// OK: name 是 String 类型
// if let &mut MyEnum::A {
// name,
// x: 0,
// } = e
}
过长的 tuple 不能被格式化输出:
fn main() {
let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); // 最多 12 个元素才能被格式化
println!("too long tuple: {:?}", too_long_tuple);
}
array 可以转换为相同长度的 tuple:
let array: [u32; 3] = [1, 2, 3];
let tuple: (u32, u32, u32) = array.into();
6 pointer #
Rust 提供如下几种指针类型:
- 引用(reference): &T 和 &mut T
- 裸指针(raw pointer): *const T(不可变)/*mut T(可变),如 *const [u8];
- 智能指针(smart pointer): Box<T>/Rc<T>/Arc<T> 和 RefCell<T> 等。
裸指针(raw pointer)与 C 指针相似,它们的使用不受安全检查,需要在 unsafe 中使用裸指针(创建时不需要:
fn main() {
let mut x = 10;
let ptr_x = &mut x as *mut i32; // 将借用转换为可变裸指针
unsafe {
ptr_x += 10;
println!("x: {}", *ptr_x);
}
}
智能指针(smart pointer)是实现了 Deref 和 Drop trait 的类型,和指针一样,支持解引用操作符 *(使用Deref trait)。
fn main() {
let b = 5i32; // 在栈上分配一个 i32 值1
let b = Box::new(5); // 在堆上分配一个 i32 值
println!("b: {}", b);
let rc = Rc::new(5); // 创建一个引用计数指针
let rc_clone = rc.clone(); // 增加引用计数
println!("rc: {}, rc_clone: {}", rc, rc_clone);
}
指针内存布局:
- 普通引用和裸指针:占用一个机器字 isize 大小;
- 切片引用 &[T]/*const [T] 和 字符串引用 &str:占用两个机器字,分别保存 内存指针 和 bytes 数量;
- Box<T>: 取决于 T 类型:
- T 是基本类型,如 i32 时,占用一个机器字,保存内存指针;
- T 是 [T] 类型时,如 Box<[i32]>, 占用两个机器字, 保存内如指针和 bytes 数量;
- Box<dyn Trait> 或 &dyn Trait: 占用两个机器字,保存实际对象的内存指针,以及该对象实现的各种方法的 vtable 指针;
let pointer_size = std::mem::size_of::<&u8>();
assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>());
assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>());
assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
Rust 的 type coercion 为引用和 raw pointer 提供了隐式自动转换, 也可以使用 as 运算符来对 type coercion 显式转换:
- &mut T 转换为 &T <- 可变引用可以转换为不可变引用
- *mut T 转换为 *const T <– 可变 raw pointer 可以转换为不可变 raw pointer
- &T 转换为 *const T <– 不可变引用 可以转换为 不可变 raw pointer
- &mut T 转换为 *mut T <– 可变引用 可以转换为 可变 raw pointer
// [T; n] 可以 unsize type coerce 到 [T]
let arry = [1, 2, 3];
let usz: &[i32] = &arry;
// &mut T -> &T
let r: &i32 = &mut 1i32;
// &T -> *const T
let rp: *const i32 = &1i32;
// &mut T -> *const T 或 *mut T
let r: *const i32 = &mut 1i32;
let r: *mut i32 = &mut 1i32;
// *mut T -> *const T
let rp: *const i32 = &mut 1i32 as *mut i32 as *const i32;
// 对于裸指针, 支持 *const T 和 *mut T 之间相互转换
let mut a = 123i32;
let arp = &a as *const i32;
let arp = arp as *mut i32;
let arp = arp as *const i32;
// 以下是 CoerceUnsized trait 实现的 type coercion 转换, 将 T 指针转换为 U 指针, U 需
// 要是 unsized type.
// &T -> &U
let u: &dyn std::fmt::Display = &123i32;
// &mut T -> &U
let u: &dyn std::fmt::Display = &mut 123i32;
// &mut T -> &mut U
let u: &mut dyn std::fmt::Display = &mut 123i32;
// &T -> *const U
let u: *const dyn std::fmt::Display = &123i32;
// &mut T -> *const U
let u: *const dyn std::fmt::Display = &mut 123i32;
// &mut T -> *mut U
let u: *mut dyn std::fmt::Display = &mut 123i32;
// Box<T> -> Box<U>
let b1 = Box::new(123i32); // i32 -> dyn std::fmt::Display
let b2: Box<dyn std::fmt::Display> = b1;
// Rc<T> -> Rc<U>
let r1 = Rc::new(123i32);
let r2: Rc<dyn std::fmt::Display> = r1;
7 struct #
struct/enum/union 是 Rust 的三种自定义类型。自定义类型名惯例是 CamelCase,否则编译时警告。
struct 三种类型:
- unit struct: 不含任何 field;
- tuple struct: 使用 tuple 来保存值;
- C-like struct: 各 field 类型可以自定义;
struct Unit;
struct Pair(i32, f32);
struct Point {
x: f32,
y: f32,
}
// 实例化
let _unit = Unit; // 对于 unit struct,只有唯一的一个实例。
let pair = Pair(1, 0.1); // 初始化 tuple struct 时,类似于函数调用。
let Pair(integer, decimal) = pair; // 解构 struct,注意前面的 Pair 不能省。
创建 struct 对象时, 必须列出每一个 field,与 field 同名的变量赋值可以使用简写形式,可以使用某个struct 对象展开来快速创建一个新的 struct 对象, 但它必须位于新 struct 初始化的最后一项且结尾不能有逗号。
struct Person {
name: String,
age: u8,
hobby: String,
}
let age = 30;
let p = Person { // Error:missing field `hobby` in initializer of `Person`
name: String::from("sunface"),
age, // 与 field 同名的变量赋值, 可以使用简写形式。
};
// 同名的 field 可以简写。
let name = String::from("Peter");
let age = 27;
let peter = Person { name, age };
// newtype idiom, 一般为其他类型添加方法
struct Years(i64);
struct Days(i64);
impl Years {
pub fn to_days(&self) -> Days {
Days(self.0 * 365)
}
}
impl Days {
pub fn to_years(&self) -> Years {
Years(self.0 / 365)
}
}
fn old_enough(age: &Years) -> bool {
age.0 >= 18
}
// 使用 struct 对象初始化另一个 struct 对象。
#[derive(Debug)]
struct User {
active: bool,
username: String,
email: String,
sign_in_count: u64,
}
fn main() {
let u1 = User {
email: String::from("[email protected]"),
username: String::from("sunface"),
active: true,
sign_in_count: 1,
};
let u2 = set_email(u1);
println!("Success! {u2:?}");
}
fn set_email(u: User) -> User {
User {
email: String::from("[email protected]"),
..u // u 必须位于最后且结尾不能有逗号
}
}
无 field 的 struct MyStruct;
等效于 struct MyStruct {};
:
struct Cookie;
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
// 等效于
struct Cookie {}
const Cookie: Cookie = Cookie {};
let c = [Cookie, Cookie {}, Cookie, Cookie {}];
struct 拥有各 field 对象的所有权,包含引用类型成员时需要指定 lifetime。嵌套带声明周期的 struct 时,外层 struct 也必须声明生命周期。为了避免为 struct 指定 lifetime,field 一般使用 owned 类型而非&T/&mut T 类型 (‘static 除外):
- ‘a: ‘b :表示 ‘a 的 lifetime 至少要比 ‘b 长;
- T: ‘a :表示 T 的生命周期要比 ‘a 长;
// 错误:r 是引用类型,但是没有指定 lifetime,编译失败。
struct S {
r: &i32
}
let s;
{
let x = 10;
s = S { r: &x };
}
assert_eq!(*s.r, 10); // bad: reads from dropped `x`
// 正确,所有引用类型的 field 都是 'static 时,struct 可以不指定 lifetime
struct S {
r: &'static i32
}
// 正确,明确指定 lifetime,r 引用对象的生命周期至少要比 struct S 对象长
struct S<'a> {
r: &'a i32
}
// 正确,明确指定多个 lifetime 参数
struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
// 错误:嵌套带 lifetime 的 struct filed 时,必须为其指定 lifetime
struct D {
s: S
}
// 正确
struct D<'a> {
s: S<'a>
}
struct 整体和各 field 需要单独设置 public (enum 是整体 public 即可), 没有设置 public 的 field 默认是私有的, 其它 module 不能访问它们。
struct 默认没有实现 Copy/Clone/Debug, 可以通过 derive macro 让编译器自动实现它们。
struct 的各 field 可以被单独 move,如果 field 类型没有实现 Copy,则可能会被 partial move, move 的field 不能再访问:
- enum 也可以被 partial move;
- array/tuple/vec 元素不能被 partial move, 但可以整体或全部没 move(如迭代);
fn main() {
#[derive(Debug)]
struct Person {
name: String,
age: Box<u8>,
}
let person = Person {
name: String::from("Alice"),
age: Box::new(20),
};
// struct 可以使用 pattern match 解构。
// name 被从 person move 出来,但是 age 是引用。
let Person { name, ref age } = person;
// 错误:person 存在部分 move,不能再使用
//println!("The person struct is {:?}", person);
// 错误:person.name 已经被 move,不能再访问
//println!("The person name is {:?}", person.name);
// OK,person.age 是被 age 借用,没有从 persion move,所以可以使用
println!("The person's age from person struct is {}", person.age);
}
8 enum #
enum 成员称为 enum variant
,可以包含数据,有三种风格:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msgs: [Message; 3] = [
Message::Quit,
Message::Move{x:1, y:3},
Message::ChangeColor(255,255,0)
];
for msg in msgs {
show_message(msg)
}
}
可以使用 enum::variant as i32/u32
来获得 tag 值:
enum Number {
Zero, // tag 默认在上一个基础上递增,第一个 tag 为 0。
One,
Two,
}
enum HttpResultCode {
Ok = 200, // 明确设置 tag 值
NotFound = 404,
Teapot = 418,
}
// 不允许多个 field 使用相同的 tag 值(但是 C 允许)
enum SharedDiscriminantError2 {
Zero, // 0
One, // 1
OneToo = 1 // 1 (collision with previous!)
}
// enum variant 可以被转换为 integer
let code = HttpResultCode::NotFound;
assert_eq!(code as i32, 404);
特殊的空 enum (无 variant) 不能作为 value 使用
, 主要的使用场景是作为不可能发生错误的
Result,如标准库类型 std::convert::Infallible
:
// std::convert::Infallible
pub enum Infallible {} // {} 不能省,但是 unit type struct 的 {} 可以省,如 struct MyStruct;
impl<T, U> TryFrom<U> for T where U: Into<T> {
type Error = Infallible;
fn try_from(value: U) -> Result<Self, Infallible> {
Ok(U::into(value)) // Never returns `Err`
}
}
// 当 !稳定后,Infallible 也可以使用 ! 的别名来定义。
pub type Infallible = !;
trait MyTrait {}
impl MyTrait for fn() -> ! {}
impl MyTrait for fn() -> std::convert::Infallible {}
// 另一个例子
enum ZeroVariants {}
let x: ZeroVariants = panic!();
// let y: u32 = x; // mismatched type error
enum 支持 pattern match, 匹配 variant 时需要指定它的各参数值:
enum WebEvent {
PageLoad,
PageUnload,
KeyPress(char),
Paste(String),
Click { x: i64, y: i64 },
}
fn inspect(event: WebEvent) {
match event {
WebEvent::PageLoad => println!("page loaded"),
WebEvent::PageUnload => println!("page unloaded"),
WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
WebEvent::Paste(s) => println!("pasted \"{}\".", s),
WebEvent::Click { x, y } => { println!("clicked at x={}, y={}.", x, y);},
}
}
// 创建 enum variant 时需要指定各类型值
fn main() {
let pressed = WebEvent::KeyPress('x');
let pasted = WebEvent::Paste("my text".to_owned());
let click = WebEvent::Click { x: 20, y: 80 };
let load = WebEvent::PageLoad;
let unload = WebEvent::PageUnload;
inspect(pressed);
inspect(pasted);
inspect(click);
inspect(load);
inspect(unload);
}
析构 enum:在 enum variant 值外部而非内部类匹配 & 或 &mut:
let x: &Option<i32> = &Some(3);
// OK: 等效为 Some(ref y), y 的类型是 &i32
if let Some(y) = x {}
// OK: 在 variant 外指定 &,y 的类型是 i32
if let &Some(y) = x {}
// ERROR: 不能在 variant 内指定 &,expected `i32`, found `&_`
if let Some(&y) = x {}
let (a, b ) = &(1, 2); // a 和 b 都是 &i32 类型
let &(c, d ) = &(1, 2); // c 和 d 都是 i32 类型
let (&c, d ) = &(1, 2); // 报错
let (ref c, d ) = &(1, 2); // OK
// 另一个例子
enum MyEnum {
A { name: String, x: u8 },
B { name: String },
}
// name 和 x 都是析构后的变量名,可以在后面的 block 中使用。name 是 &mut String 类型。
fn a_to_b(e: &mut MyEnum) {
if let MyEnum::A {name, x: 0, } = e {
*e = MyEnum::B {
name: std::mem::take(name), // take 参数类型是 &mut T, 而 name 类型是 &mut String 故满足
}
}
// if let &mut MyEnum::A {
// name, // OK: name 是 String 类型
// x: 0,
// } = e
}
enum variant 可以使用 use 按需或一次性导入,这样不需要每次指定 enum::variant 的 enum:: 部分:
#![allow(dead_code)]
enum Status {
Rich,
Poor,
}
enum Work {
Civilian,
Soldier,
}
fn main() {
use crate::Status::{Poor, Rich};
use crate::Work::*; // 一次导入所有 variant
let status = Poor;
let work = Civilian;
match status {
Rich => println!("The rich have lots of money!"),
Poor => println!("The poor have no money..."),
}
}
enum 可见性:只需为 enum 整体指定 pub 可见性即可,各 variant 的可见性继承自整体。(struct 需要为每个 field 单独指定可见性)。
enum 内存布局:tag 字段和能容纳所有 variant 的内存块,其中 tag 是 Rust 内部用来区分 variant。
9 union #
union 类型:是用一块内存区域来保存不同类型值的类型,也就是可以按照不同的类型对这块内存进行解释。在创建 union 对象时,必须指定某一个 field,但是后续可以按照其他 field 的类型来解释以前给 union 的赋值:
// f 和 i 共享同一块内存区域
union FloatOrInt {
f: f32,
i: i32,
}
let mut one = FloatOrInt { i: 1 };
assert_eq!(unsafe { one.i }, 0x00_00_00_01);
one.f = 1.0;
assert_eq!(unsafe { one.i }, 0x3F_80_00_00);
union 类型的大小取决于最大 field 的空间需求,比如下面 union 的大小为 64 bytes:
union SmallOrLarge {
s: bool,
l: u64
}
必须在 unsafe 中访问 union field,这是由于 union 不像 enum,内存模型不包含 tag,所以编译器不知道存入和访问的是哪一个 field:
let u = SmallOrLarge { l: 1337 };
println!("{}", unsafe {u.l}); // prints 1337
使用 #[repr(C)] 来设置 union 使用 C 内存布局:
#[repr(C)]
union SignExtractor {
value: i64,
bytes: [u8; 8]
}
fn sign(int: i64) -> bool {
let se = SignExtractor { value: int};
println!( "{:b} ({:?})", unsafe { se.value }, unsafe { se.bytes });
unsafe { se.bytes[7] >= 0b10000000 }
}
assert_eq!(sign(-1), true);
assert_eq!(sign(1), false);
assert_eq!(sign(i64::MAX), false);
assert_eq!(sign(i64::MIN), true);
union 用不同的方式来解释同一块内存区域,编译器不知道如何 Drop union 对象,所以各 field 必须都必须是实现 Copy 的类型。如果要保存 String 类型,则可以参考 std::mem::ManuallyDrop。
可以使用 match pattern 来匹配 union,每个 pattern 只能包含一个 field:
- 如果只指定 filed 但是没有值,则一定可以匹配成功。
unsafe {
match u {
SmallOrLarge { s: true } => { println!("boolean true"); } // 如果按照 s 来解释,能够匹配 true
SmallOrLarge { l: 2 } => { println!("integer 2"); } // 如果按照 l 来解释,能够匹配 2
_ => { println!("something else"); }
}
}
borrow uinon 某个 filed 等效于 borrow 整个 union,所以在 borrow 某个 field 后就不能再 borrow 其它field。