如何在String、&str、Vec<u8>和&[u8]之间进行转换?

112

像我这样的新Rust程序员在处理这些类型时感到困惑:String, &str, Vec<u8>, &[u8]

希望能有所领悟,突然明白为什么某些库调用使用其中的一种。在那之前,我需要帮助来映射每个成语化的转换。

鉴于这些类型:

let st: &str = ...;
let s:  String = ...;
let u:  &[u8] = ...;
let v:  Vec<u8> = ...;

我认为我已经搞明白了,但它们是否符合习惯用法?

&str    -> String    String::from(st)
&str    -> &[u8]     st.as_bytes()
String  -> &str      s.as_str()
&[u8]   -> &str      str::from_utf8(u)
Vec<u8> -> String    String::from_utf8(v)

我最终希望得到这些类型的完整转换表:

&str    -> String
&str    -> &[u8]
&str    -> Vec<u8>
String  -> &str
String  -> &[u8]
String  -> Vec<u8>
&[u8]   -> &str
&[u8]   -> String
&[u8]   -> Vec<u8>
Vec<u8> -> &str
Vec<u8> -> String
Vec<u8> -> &[u8]
1个回答

169

来自 &str

  • &str -> String许多同样有效的方法String::from(st)st.to_string()st.to_owned()
    • 但我建议您在单个项目中坚持使用其中一个。 String::from 的主要优点是您可以将其用作 map 方法的参数。因此,您通常可以使用 x.map(String::from) 而不是 x.map(|s| String::from(s))
  • &str -> &[u8] 可以使用 st.as_bytes() 实现
  • &str -> Vec<u8>&str -> &[u8] -> Vec<u8> 的组合,即 st.as_bytes().to_vec()st.as_bytes().to_owned()

String

  • String -> &str 应该使用强制类型转换&s或者s.as_str()(如果无法进行强制类型转换)
  • String -> &[u8]&str -> &[u8]相同:s.as_bytes()
  • String -> Vec<u8> 有一个自定义方法:s.into_bytes()

&[u8]

  • &[u8] -> Vec<u8>可以通过u.to_owned()u.to_vec()实现。它们的作用相同,但to_vec稍微优于to_owned,因为它在返回类型上更加明确。
  • &[u8] -> &str实际上不存在,正确的写法应该是&[u8] -> Result<&str, Error>,可以通过str::from_utf8(u)来实现。
    • str::from_utf8(u).unwrap()可以使用,但最好使用更好的错误处理方法(请参见错误处理-Result类型)。
  • &[u8] -> String可以通过&[u8] -> Result<&str, Error> -> Result<String, Error>实现。

来自 Vec<u8>

  • Vec<u8> -> &[u8] 应该使用可以进行强制转换的&v,或者不可用时使用as_slice
  • Vec<u8> -> &strVec<u8> -> &[u8] -> Result<&str, Error> 相同,即 str::from_utf8(&v)
  • Vec<u8> -> String 实际上不存在,应该使用 Vec<u8> -> Result<String, Error> 通过 String::from_utf8(v)
    • String::from_utf8(v).unwrap() 可以工作,但最好使用更好的错误处理方式(参见错误处理-Result类型)。

强制类型转换只有在目标类型不是通用类型,但明确声明为&str&[u8]时才可用。Rustonomicon有一章关于强制类型转换,提供了有关强制类型转换点的更多详细信息。


简而言之

&str    -> String  | String::from(s) or s.to_string() or s.to_owned()
&str    -> &[u8]   | s.as_bytes()
&str    -> Vec<u8> | s.as_bytes().to_vec() or s.as_bytes().to_owned()
String  -> &str    | &s if possible* else s.as_str()
String  -> &[u8]   | s.as_bytes()
String  -> Vec<u8> | s.into_bytes()
&[u8]   -> &str    | s.to_vec() or s.to_owned()
&[u8]   -> String  | std::str::from_utf8(s).unwrap(), but don't**
&[u8]   -> Vec<u8> | String::from_utf8(s).unwrap(), but don't**
Vec<u8> -> &str    | &s if possible* else s.as_slice()
Vec<u8> -> String  | std::str::from_utf8(&s).unwrap(), but don't**
Vec<u8> -> &[u8]   | String::from_utf8(s).unwrap(), but don't**

* target should have explicit type (i.e., checker can't infer that)

** handle the error properly instead

1
好的,但是如何将单个u8变量转换为字符串?to_string()似乎不起作用,因为它会报错“在当前范围内找不到类型为u8的as_string方法”...我想要的是将一个小数字(例如32)更改为字符串“32”。 - piotao
@piotao,你需要调用format!("{}", 5_u8),它会返回一个拥有所有权的String - rdxdkr
2
如果有其他人想知道,你可以通过 String::from_utf8_lossy(&*s)Vec<u8> 转换为丢失信息的字符串。 - Schneems

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接