Rust标准库

单线程

  • 常见的需求但容易忘记的代码片段
字符串 需求代码片段
拼接字符串(任何实现了 Displayformat!("{x}{y}")
追加字符串(任何实现了 Display 到 任何实现了 Writewrite!(x, "{y}")
按分隔符模式分割s.split(pattern)
  ...with &strs.split("abc")
  ...with chars.split('/')
  ...with closures.split(char::is_numeric)
按空格切割s.split_whitespace()
用换行符分割s.lines()
按正则表达式分割Regex::new(r"\s")?.split("one two three")
  1. 如果 xy 之后不打算用到,考虑使用 write!std::ops::Add
  2. 需要 regex crate

I/O 需求代码片段
创建一个新文件File::create(PATH)?
通过OpenOptions创建OpenOptions::new().create(true).write(true).truncate(true).open(PATH)?

需求代码片段
宏 可变参数macro_rules! var_args { ($($args:expr),*) => {{ }} }
  使用参数,如多次调用 f$( f($args); )*

Esoterics 需求代码片段
干净的闭包捕获wants_closure({ let c = outer.clone(); move || use_clone(c) })
try 闭包中的修复推断iter.try_for_each(|x| { Ok::<(), Error>(()) })?;
如果 T 实现了 Copy,则可迭代和编辑 &mut [T]Cell::from_mut(mut_slice).as_slice_of_cells()
获取带有长度的子切片&original_slice[offset..][..length]
敏锐的确保特征 T 是对象安全的const _: Option<&dyn T> = None;

线程安全

例子Send*!Send
Sync*大多数类型是 ...Arc<T>1,2Mutex<T>MutexGuard<T>RwLockReadGuard<T>
!SyncCell<T>2RefCell<T>Rc<T>&dyn Trait*const T*mut T

*一个 T: Send 的实例可以被移动到另一个线程,而一个 T: Sync 意味着 &t 可以被移动到移动到另一个线程

  1. 如果 TSync
  2. 如果 TSend
  3. 如果你需要去 send 一个裸指针,创建一个新类型 struct Ptr(*const u8)unsafe impl Send for Ptr {},仅需确保你可以 send 它

迭代器

获取迭代器
基本用法
假设有一个类型 C 的集合c
  • c.into_iter() — 将集合c转换为一个Iteratoriconsumesc。需要实现了 CIntoIterator。条目的类型取决于 C 是什么。获取迭代器的"标准化"方法
  • c.iter() — 一些集合提供的优雅方法,返回借用的迭代器,不会消耗 c
  • c.iter_mut() — 同上,但是可变借用的迭代器允许更改集合
  • The Iterator
    一旦你有一个 i:
  • i.next() — 返回下一个元素c提供的 Some(x),或者如果已经完成了则返回None
  • For 循环
  • for x in c {} — 语法糖,调用c.into_iter()并且循环i直到为 None
  • *如果它看起来好像没有消耗 c,那是因为类型是 Copy,如 如果你调用 (&c).into_iter(),它将在 &c 上调用 into_iter() (这将消耗引用并将其转换为迭代器),但c仍保持不变。


    实现迭代器
    基本用法
    假设你有一个 `struct Collection {}`
  • struct IntoIter {} — 创建一个结构来保存你的迭代状态(如 索引)以进行值的迭代
  • impl Iterator for IntoIter {} — 实现 Iterator::next(),这样它就可以生成元素
  • Collection<T>
    IntoIter<T> ⌾Iterator Item = T;
    共享的和可变迭代器
  • struct Iter<T> {} — 为共享迭代器去创建持有 &Collection<T> 的结构
  • struct IterMut<T> {} — 同上,为了可变迭代器去创建持有 &mut Collection<T> 的结构
  • impl Iterator for Iter {} — 实现共享迭代器
  • impl Iterator for IterMut {} — 实现可变迭代器
  • 另外你可能会希望添加一些便捷的方法
  • Collection::iter(&self) -> Iter
  • Collection::iter_mut(&mut self) -> IterMut
  • Iter<T> ⌾Iterator Item = &T;
    IterMut<T> ⌾Iterator Item = &mut T;
    使用循环的写法
  • impl IntoIterator for Collection {} — 现在for x in c {}是有用的
  • impl IntoIterator for &Collection {} — 现在for x in &c {}是有用的
  • impl IntoIterator for &mut Collection {} — 现在for x in &mut c {}是有用的 Collection<T> ⌾IntoIterator Item = T; To = IntoIter<T> Iterate over T
    &Collection<T> ⌾IntoIterator Item = &T; To = Iter<T> Iterate over &T
    &mut Collectn<T> ⌾IntoIterator Item = &mut T; To = IterMut<T> Iterate over &mut T
  • 数字转换

    需要转换成的→u8 … i128f32 / f64String
    u8 … i128u8::try_from(x)?x as f32x.to_string()
    f32 / f64x as u8x as f32x.to_string()
    Stringx.parse::<u8>()?x.parse::<f32>()?x
    1. 如果打印是正确的话 from()会直接输出,如 u32::from(my_u8)
    2. 截断(11.9_f32 as u8 gives 11),充满(1024_f32 as u8 gives 255)
    3. 可能会有不合适的数字(u64::MAX as f32)或产生 Inf (u128::MAX as f32)

    字符串转换

    • 如果你想要一个指定类型的字符串
    已经存在的类型 x要转换成 String
    Stringx
    CStringx.into_string()?
    OsStringx.to_str()?.to_string()
    PathBufx.to_str()?.to_string()
    Vec<u8>String::from_utf8(x)?
    &strx.to_string()
    &CStrx.to_str()?.to_string()
    &OsStrx.to_str()?.to_string()
    &Pathx.to_str()?.to_string()
    &[u8]String::from_utf8_lossy(x).to_string()

    已存在的类型 x要转换成 CString
    StringCString::new(x)?
    CStringx
    OsStringCString::new(x.to_str()?)?
    PathBufCString::new(x.to_str()?)?
    Vec<u8>CString::new(x)?
    &strCString::new(x)?
    &CStrx.to_owned()
    &OsStrCString::new(x.to_os_string().into_string()?)?
    &PathCString::new(x.to_str()?)?
    &[u8]CString::new(Vec::from(x))?
    *mut c_charunsafe { CString::from_raw(x) }

    已存在的类型 x要转换成 OsString
    StringOsString::from(x)
    CStringOsString::from(x.to_str()?)
    OsStringx
    PathBufx.into_os_string()
    Vec<u8>?
    &strOsString::from(x)
    &CStrOsString::from(x.to_str()?)
    &OsStrOsString::from(x)
    &Pathx.as_os_str().to_owned()
    &[u8]?

    已存在的类型 x要转换成 PathBuf
    StringPathBuf::from(x)
    CStringPathBuf::from(x.to_str()?)
    OsStringPathBuf::from(x)
    PathBufx
    Vec<u8>?
    &strPathBuf::from(x)
    &CStrPathBuf::from(x.to_str()?)
    &OsStrPathBuf::from(x)
    &PathPathBuf::from(x)
    &[u8]?

    已存在的类型 x要转换成 PathBuf
    StringPathBuf::from(x)
    CStringPathBuf::from(x.to_str()?)
    OsStringPathBuf::from(x)
    PathBufx
    Vec<u8>?
    &strPathBuf::from(x)
    &CStrPathBuf::from(x.to_str()?)
    &OsStrPathBuf::from(x)
    &PathPathBuf::from(x)
    &[u8]?

    已存在的类型 x要转换成 Vec
    Stringx.into_bytes()
    CStringx.into_bytes()
    OsString?
    PathBuf?
    Vec<u8>x
    &strVec::from(x.as_bytes())
    &CStrVec::from(x.to_bytes_with_nul())
    &OsStr?
    &Path?
    &[u8]x.to_vec()

    已存在的类型 x要转换成 &str
    Stringx.as_str()
    CStringx.to_str()?
    OsStringx.to_str()?
    PathBufx.to_str()?
    Vec<u8>std::str::from_utf8(&x)?
    &strx
    &CStrx.to_str()?
    &OsStrx.to_str()?
    &Pathx.to_str()?
    &[u8]std::str::from_utf8(x)?

    已存在的类型 x要转换成 &CStr
    StringCString::new(x)?.as_c_str()
    CStringx.as_c_str()
    OsStringx.to_str()?
    PathBuf?,4
    Vec<u8>CStr::from_bytes_with_nul(&x)?
    &str?,4
    &CStrx
    &OsStr?
    &Path?
    &[u8]?

    已存在的类型 x要转换成 PathBuf
    StringPathBuf::from(x)
    CStringPathBuf::from(x.to_str()?)
    OsStringPathBuf::from(x)
    PathBufx
    Vec<u8>?
    &strPathBuf::from(x)
    &CStrPathBuf::from(x.to_str()?)
    &OsStrPathBuf::from(x)
    &PathPathBuf::from(x)
    &[u8]CStr::from_bytes_with_nul(x)?
    *const c_charunsafe { CStr::from_ptr(x) }

    已存在的类型 x要转换成 &OsStr
    StringOsStr::new(&x)
    CString?
    OsStringx.as_os_str()
    PathBufx.as_os_str()
    Vec<u8>?
    &strOsStr::new(x)
    &CStr?
    &OsStrx
    &Pathx.as_os_str()
    &[u8]?

    已存在的类型 x要转换成 &Path
    StringPath::new(x)
    CStringPath::new(x.to_str()?)
    OsStringPath::new(x.to_str()?)
    PathBufPath::new(x.to_str()?)
    Vec<u8>?
    &strPath::new(x)
    &CStrPath::new(x.to_str()?)
    &OsStrPath::new(x)
    &Pathx
    &[u8]?

    已存在的类型 x要转换成 &[u8]
    Stringx.as_bytes()
    CStringx.as_bytes()
    OsString?
    PathBuf?
    Vec<u8>&x
    &strx.as_bytes()
    &CStrx.to_bytes_with_nul()
    &OsStrx.as_bytes()
    &Path?
    &[u8]x

    已存在的类型 x要转换成 Other( *const c_char )
    CStringx.as_ptr() ( *const c_char )

    *如果类型能被推断出来则可使用简写 x.into()

    *如果类型能被推断出来则可使用简写 x.as_ref()

    1. 如果调用了unsafe,你应该或必须确保原始数据带有字符串类型的有效表示(如 一个 UTF-8 的字符串)
    2. 仅在一些平台( std::os::<your_os>::ffi::OsStrExt )存在辅助方法去获取底层 OsStr 的原始表示。从那里使用表格的其它部分,如下
    use std::os::unix::ffi::OsStrExt;
    let bytes: &[u8] = my_os_str.as_bytes();
    CString::new(bytes)?
    1. c_char 必须来自之前的 CString,如果来自FFI,请参阅 &CStr
    2. x 因为缺少终止符 0x0,没有已知的简写,可能最好的方式是通过 CString
    3. 必须确保向量实际上以 0x0 结尾

    字符串输出

    APIs

    • Rust使用这些APIs将类型转换为字符串化输出,统称为格式宏
    输出备注
    format!(fmt)String"to String" 的转换器
    print!(fmt)Console写到标准输出
    println!(fmt)Console写到标准输出,换行
    eprint!(fmt)Console写到标准错误输出
    eprintln!(fmt)Console写到标准错误输出,换行
    write!(dst, fmt)Buffer还有 use std::io::Write;
    writeln!(dst, fmt)Buffer还有 use std::io::Write;,换行

    方法备注
    x.to_string()生成 String,实现任何的 Display 类型

    *fmt 是字符串文字,例如 "hello {}",指定输出和其他参数

    可打印的类型

    *在友好的 format! 中,类型通过 trait Display "{}"Debug "{:?}" 转换,非详尽列表如下

    类型实现
    StringDebug, Display
    CStringDebug
    OsStringDebug
    PathBufDebug
    Vec<u8>Debug
    &strDebug, Display
    &CStrDebug
    &OsStrDebug
    &PathDebug
    &[u8]Debug
    boolDebug, Display
    charDebug, Display
    u8 … i128Debug, Display
    f32, f64Debug, Display
    !Debug, Display
    ()Debug

    *简而言之,几乎所有东西都是Debug,更多特殊类型可能需要特殊处理或转换到 Display

    格式化

    • 格式宏中的每个参数指示符要么是空的 {},{argument},要么遵循基本语法
    { [argument] ':' [[fill] align] [sign] ['#'] [width [$]] ['.' precision [$]] [type] }
    元素含义
    argument数字( 0, 1, ... ),变量或名字,如 print!("{x}")
    fill如果指定了宽度,用(如 0 )来填充空白的字符
    align如果指定了宽度,则左(<)、中(^)或右(>)
    sign 可以是 +,标志总是被打印
    #代替格式化,如 美化的 Debug 格式器 ? 或前缀十六进制使用 0x
    width最小的宽度(≥0),填充(默认为空格)如果以 0 开头,则补零
    precision数字的小数位(≥0),或者形容非数字的最大宽度
    $解释宽度(width)或精度(precision)作为参数标识符,而不是允许动态格式化
    typeDebug 格式化、十六进制(x)、二进制(b)、八进制(o)、指针(p)、exp(e)

    格式化示例解释
    {}使用 Display 打印下一个参数
    {x}同上,但在范围内使用变量 x
    {:?}使用 Debug 打印下一个参数
    {2:#?}使用 Debug 格式化,较好的打印第三个参数
    {val:^2$}将命名参数 val 居中,宽度由第三个参数指定
    {:<10.3}左对齐宽度为 10,精度为 3
    {val:#x}将参数 val 格式化为十六进制,带前缀 0x (替代格式 x

    完整示例解释
    println!("{}", x)使用 Display 在标准输出打印并且追加一个新行
    println!("{x}")同上,但在范围内使用变量 x
    format!("{a:.3} {b:?}")用三位数字转换 PI,增加空格,b 使用 Debug,返回 String