Rust入门失败之String and str

  • 所有Stringstr类型都保证内部持有正确的UTF-8格式字符串. 所有的safe操作都保证这一点, 即不会引入错误格式的UTF-8

  • String的内部实现其实就是Vec<u8>

  • str则是borrow的String引用. &str不能Clone, 因为clone(&T)方法需要一个返回T对象, 而str又是unsized的. 可以通过slice.to_owned()获取一份重新分配的拷贝.

  • String::new()返回的是一个空的字符串, 还没有分配任何堆上的内存.

  • 不能通过单个下标访问slice的某个字符(slice[i]), 因为UTF-8的字符是不定长的. 可以通过chars()方法返回字符的迭代器:

    1
    2
      let parenthesized = "Rust (饂)";
    assert_eq!(parenthesized[6..].chars().next(), Some('饂'));
  • String实现了Add<&str>AddAssign<&str>的Trait, 因此可以很自然地用+拼接字符串. 但是有两点要注意:

    • 左边的操作符不能是&str, 一定要是一个String对象. 因为会consume这个对象, 获取其所有权, 且会重复利用它的buffer, 如果capacity足够大, 就不需要额外再开辟内存.

      1
      2
      3
      4
      5
      let string = "partners".to_string();
      // 不能这样写
      let parenthetical = "(" + string + ")";
      // 需要转为String
      let parenthetical = "(".to_string() + string + ")";
    • 对右边的操作符只是borrow, 也就意味着它的内容会被拷贝到前者的buffer末尾.

  • String转成其它类型需要实现std::str::FromStr Trait. 所有的基础类型都实现了这个Trait.

  • 其它类型转成String有三种方法:

    • 实现std::fmt::Display trait. 所有的机器数字类型都实现了这个trait, 可以直接显示. 而像Box<T>, Rc<T>, Arc<T> 这类智能指针类型, 只有T实现了Display trait, 这个类型才能Dispaly.
    • 实现std::str::ToString trait.如果实现了上面的Display trait, 那么Rust自动帮我们实现这个trait.
    • 实现std::fmt::Debug trait. 所有标准库可访问的pub 类型都实现了这个方法. 通常如果我们是库的开发者, 对外部开放的类型也都应该实现这个trait, 方便他人打印调试.
  • 如果做数据压缩之类的, 需要访问字符串内部字节数据有两种方法:

    • slice.as_bytes(): borrow其内部的Vec, 返回&[u8]. immutable, 且需要注意生命周期.

    • string.into_bytes(): 这个成本比较低, 直接consume这个String对象, 把内部的Vec<u8>交出来返回, 没有任何多余的成本.

      1
      2
      3
      pub fn into_bytes(self) -> Vec<u8> {
      self.vec
      }
  • 同样从原始的字节也可以构造String, 有下面几种方法, 但是都要注意错误检查:

    • std::str::from_utf8(v: &[u8]) -> Result<&str, Utf8Error>: 从这里可以看到, 一是会做错误检查, 如果不是有效的UTF-8格式字节, 则会返回Err; 二是, 返回的&str&[u8]有同样的生命周期.
    • String::from_utf8(vec: Vec<u8>) -> Result: 一, 同样做错误检查; 二, 参数直接捕获Vec所有权, 并把它的buffer做为String内部buffer, 省去了开辟, 非常高效;