跳过正文

内置类型:type

··16432 字
Rust
目录
rust-lang - 这篇文章属于一个选集。
§ 3: 本文

语言内置类型:

  1. 基础类型:Boolean, Numeric, Textual, Never;
  2. 序列类型:Tuple, Array, Slice;
  3. 自定义类型:Struct, Enum, Union;
  4. 函数类型:Functions, Closures;
  5. 指针类型:References, Raw pointers, Function pointers;
  6. Trait 类型:Trait objects, impl Trait;

注:String、Vec 等是标准库类型,而非语言内置类型。

栈变量类型:基础类型, array/struct/tuple/enum/union;

堆变量类型:

  1. 字符串:String;
  2. 容器:Vec/HashMap/HashSet;
  3. Slice;
  4. 智能指针: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 main() {
    println!("{:p}, {:p}", &(), &()); // 打印地址相同, 说明是唯一类型值

    print_message();

    // 显式使用单元类型和单元值
    let my_unit: () = ();

    // 函数参数接受单元类型值
    take_unit(());

    // 泛型类型也可以使用单元类型, 常用于不需要返回实际值的 Ok.
    let result: Result<(), &str> = Ok(());
    match result {
        Ok(_) => println!("Operation was successful."),
        Err(e) => println!("Error occurred: {}", e),
    }
}

// 这个函数隐式返回单元类型 ()
fn print_message() {
    println!("Hello, world!");
}

字面量可以加类型后缀, 如 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;

    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 构建的二进制时 Rust 检查整数溢出并导致 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 类型的转换;

// `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

// let val: Box<dyn Any + 'a> = *val as Box<dyn Any + 'a>; // 错误

let circle = Box::new(circle) as Box<dyn Circle>; // OK: circle 可以 usized 协变到 dyn Circle
let a = *const [u16] as *const [u8]  // OK:

复杂类型转换需要使用 From/Into/TryFrom/TryInto/AsRef/AsMut trait 来进行类型转换。

  1. from() 用于无风险的转换,它不会产生错误,但是可能会 panic;
  2. try_from() 方法会返回一个 Result 类型,当转换失败时(例如,因为类型溢出或数据丢失),它会返回一个错误,程序员可以显式检查和处理。
use std::convert::TryInto; // 需要先导入 Trait
// From/Into 由标准库 prelude 自动导入,不需要手动导入。

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>() 方法可以将字符串解析转换为其它类型值。
    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 在 u8/u32 相互转换。使用 as 将 char 转换为整型的字符码点, 使用 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 类型,包括指向内存区域的指针和 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();
greetings(&s); // Box<str> 实现了 Deref<Target=str>, 所以 &Box<str> 等效于 &str

其它:

  1. b'x' :byte char,只能存 ASCII code point,对应 u8 类型,如 104 == b’h’;
  2. b"xyz" : byte string,只能是 ASCII 字符串,对应 &[u8; N] 类型,如 &[b’x’, b’y’, b’z’];
  3. r###"\a\b\c"### : raw string,不对字符串内容转义,r 后面的 # 数量可变, 但只能使用连续的 # 字符;
  4. br##"\a\b\c\t\n"## : raw byte string,只能是 ASCII 内容,类型为 &[u8, 10], 不对字符串转义,必须是 br 而不能是 rb;
  5. c"hello" :C string,以 NULL 结尾的 C 字符串。
  6. 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);

内存布局:

  1. String:三部分:指向堆内存的指针,内存的长度(bytes),内存的容量(bytes,因为是可变长度类型)。
  2. &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); // debug 打印
}

2.1 str 方法
#

常用方法:

  1. len() : 返回 bytes 数量。
  2. as_bytes() -> &[u8]
  3. as_ptr()/as_mut_ptr():返回 raw pointer: *const u8 和 *mut u8
  4. get()/get_mut(): 安全返回子串
  5. chars()/bytes():返回 char 和 byte 的迭代器;
  6. split_whitespace(): 返回空白字符分割的子串迭代器,连续的空白字符等效为一个;
  7. lines(): 返回行迭代器,行尾不包括换行;
  8. contains()/starts_with()/ends_with(): 检查 pattern, pattern 支持多种类型
  9. find()/rfind(): 返回匹配 pattern 的 index;
  10. match()/rmatch(): 返回匹配 pattern 的子串迭代器;
  11. trim_XX()/strip_XX(): 删除空格、删除前后缀;
  12. parse::<T>(): 将字符串转换为 T 类型,T 必须要实现 FromStr trait;
  13. replace(): 将 pattern 替换为子串;
  14. 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));
// indices not on UTF-8 sequence boundaries
assert!(v.get(1..).is_none());
assert!(v.get(..8).is_none());
// out of bounds
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";
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]
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 间转换:

  1. String -> &str: String.as_str();
  2. String::from(“Sunfei”) 或 “Sunface”.to_string();

创建 String:

  1. &str.to_string()
  2. &str.to_owned()
  3. format!()
  4. Array/slice/Vec 的 .concat() 和 .join()
  5. 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() 来获取它们的值:

  1. 指向堆连续内存的地址;
  2. 内存 byte 长度;
  3. 内存 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 方法:

  1. new()/with_capacity()
  2. len()/capacity()/is_empty()
  3. from_utf8_XX()
  4. into_raw_parts()/from_raw_parts()
  5. into_bytes()/into_boxed_str()/as_bytes()/as_str()/as_mut_str()
  6. push()/push_str()
  7. reserve()/shrink_to()/truncate()/clear()
  8. 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。

array index 返回 slice,即 a[start..end] ~返回一个 dynamic size 的 slice 类型 [T],故一般使用 ~&[T]Box<[T]> 。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];
    for number in numbers { // numbers.iter()/numbers.iter_mut()/numbers.into_iter()
        println!("number: {}", number);
    }
}

Rust 不允许 Array/Vec/HashMap/HashSet 中的元素被 partial move 出来(全部 move 出来是 OK 的,如通过迭代),所以如果 array 元素不支持 Copy,则 index 操作后再赋值转移会失败:

  • 但允许 struct/tuple/union 中的 field 被部分 move 出来,只不过被 move 的成员不能再读取;
  • & 和 &mut 借用的对象如果没有实现 Copy,都不允许 move 出来;

解决办法是:

  1. 使用 std::mem::replace() 方法来用同类型对象来替换(返回元素 T);
  2. 或者使用 slice pattern match 来提取;
  3. 或者使用 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 的行为;
  • 但是反过来 slice [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);
}

fn print_type_of<T>(v: &T) -> String {
    format!("{}", std::any::type_name_of_val(v)) // 传入的 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[1..],&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/Vec 可以被 type coerse 到 [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 也是在tuple 外部匹配 & 或 &mut 的:

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 提供如下几种指针类型:

  1. 引用(reference): &T 和 &mut T
  2. 裸指针(raw pointer): *const T(不可变)/*mut T(可变),如 *const [u8];
  3. 智能指针(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);
}

指针内存布局:

  1. 普通引用和裸指针:占用一个机器字 isize 大小;
  2. 切片引用 &[T]/*const [T] 和 字符串引用 &str:占用两个机器字,分别保存 内存指针 和 bytes 数量;
  3. Box<T>: 取决于 T 类型:
    1. T 是基本类型,如 i32 时,占用一个机器字,保存内存指针;
    2. T 是 [T] 类型时,如 Box<[i32]>, 占用两个机器字, 保存内如指针和 bytes 数量;
    3. 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 显式转换:

  1. &mut T 转换为 &T <- 可变引用可以转换为不可变引用
  2. *mut T 转换为 *const T <– 可变 raw pointer 可以转换为不可变 raw pointer
  3. &T 转换为 *const T <– 不可变引用 可以转换为 不可变 raw pointer
  4. &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 三种类型:

  1. unit struct: 不含任何 field;
  2. tuple struct: 使用 tuple 来保存值;
  3. 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。

rust-lang - 这篇文章属于一个选集。
§ 3: 本文

相关文章

不安全:unsafe
··824 字
Rust
Rust
借用:refer/borrow
··3120 字
Rust
Rust 引用类型和借用
函数、方法和闭包:function/method/closure
··6964 字
Rust
Rust 函数、方法和闭包
包和模块:package/crate/module
··1958 字
Rust
Rust 项目的包和模块组织结构