rs.nkmk.me

RustでStringとVec<u8>を相互に変換

Posted: | Tags: Rust, 文字列, ベクタ

Rustにおいて、文字列StringはUTF-8として有効なバイトのベクタVec<u8>である。StringVec<u8>を相互に変換するにはinto_bytesString::from_utf8を使う。

&str&[u8]の相互変換については以下の記事を参照。

以下のサンプルコードでは、説明のため、型推論によって省略できるときも明示的に型注釈を記述している場合がある。また、簡単のためunwrapを使っている。必要であればその他のメソッドやmatchなどで処理すればよい。

StringをVec<u8>に変換: into_bytes

StringVec<u8>に変換するにはinto_bytesを使う。

let s: String = String::from("abc😀");
let v: Vec<u8> = s.into_bytes();
assert_eq!(v, [97, 98, 99, 240, 159, 152, 128]);

他のinto_***という名前のメソッドと同じく、into_bytesの引数はself。所有権が移動し、元のStringは使えなくなるので注意。

なお、as_bytesというメソッドもあり、こちらはバイトのスライス&[u8]を返す。

let s: String = String::from("abc😀");
let b: &[u8] = s.as_bytes();
assert_eq!(b, [97, 98, 99, 240, 159, 152, 128]);

他のas_***という名前のメソッドと同じく、as_bytesの引数は&self。所有権は移動しない。

Vec<u8>をStringに変換: String::from_utf8, String::from_utf8_lossy

String::from_utf8

Vec<u8>Stringに変換するにはString::from_utf8を使う。

StringはUTF-8として有効であることが保証されている(=有効でなければいけない)。したがって、UTF-8として有効なVec<u8>Stringに変換できるが、有効でない場合は変換できない。

from_utf8の返り値の型はResult。UTF-8として有効でないベクタに対してはエラーを返す。

let v: Vec<u8> = vec![97, 98, 99, 240, 159, 152, 128];
let s: String = String::from_utf8(v).unwrap();
assert_eq!(s, "abc😀");

let v: Vec<u8> = vec![97, 98, 99, 255];
let is_err: bool = String::from_utf8(v).is_err();
assert!(is_err);

unsafeな関数として、UTF-8として有効かどうかのチェックを行わないString::from_utf8_uncheckedも提供されている。UTF-8として有効であることが確実で、チェックのためのオーバーヘッドを避けたい場合に使う。

let v: Vec<u8> = vec![97, 98, 99, 240, 159, 152, 128];
let s: String = unsafe { String::from_utf8_unchecked(v) };
assert_eq!(s, "abc😀");

from_utf8from_utf8_uncheckedの引数の型はVec<u8, Global>。参照ではなく、所有権が移動するので注意。

なお、std::str::from_utf8を使うとVec<u8>&strに変換することも可能。

let v: Vec<u8> = vec![97, 98, 99, 240, 159, 152, 128];
let s: &str = std::str::from_utf8(&v).unwrap();
assert_eq!(s, "abc😀");

詳細は以下の記事を参照。

String::from_utf8_lossy

String::from_utf8_lossyを使うと、UTF-8として有効でない部分を「�(U+FFFD)」に置き換えて変換できる。有効な場合はそのまま。

let v: Vec<u8> = vec![97, 98, 99, 240, 159, 152, 128];
let s: String = String::from_utf8_lossy(&v).into_owned();
assert_eq!(s, "abc😀");

let v: Vec<u8> = vec![97, 98, 99, 255];
let s: String = String::from_utf8_lossy(&v).into_owned();
assert_eq!(s, "abc�");

from_utf8_lossyの引数の型は&[u8]。配列とベクタの参照(&[u8; N], &Vec<u8>)も渡せる。参照なので所有権は移動しない。

let b: [u8; 4] = [97, 98, 99, 255];
let s: String = String::from_utf8_lossy(&b).into_owned();
assert_eq!(s, "abc�");

from_utf8_lossyの返り値の型はCow<'_, str>

This function returns a Cow<'a, str>. If our byte slice is invalid UTF-8, then we need to insert the replacement characters, which will change the size of the string, and hence, require a String. But if it’s already valid UTF-8, we don’t need a new allocation. This return type allows us to handle both cases. String::from_utf8_lossy in std::string - Rust

上の例ではinto_ownedStringに変換しているが、参照が必要な場合はそのまま&を付けて渡せばよい。

let mut s = String::from("xyz_");
let b: [u8; 4] = [97, 98, 99, 255];
let cow = String::from_utf8_lossy(&b);

s.push_str(&cow);

assert_eq!(s, "xyz_abc�");

関連カテゴリー

関連記事