LoginSignup
6
3

More than 1 year has passed since last update.

[Rust] 文字列スライス str から文字列 String への変換とその仕組み

Posted at

本記事では文字列スライス str から文字列 String に変換する方法とその仕組みについてまとめます。

文字列 String から文字列スライス str への変換については別記事にしました。

参考「[Rust] 文字列 String から文字列スライス str へ変換される仕組み - Qiita

0. まとめ

基本的な型変換
let ss: &str = "str";

let s = ss.to_string();
// or
let s = String::from(ss);
// or
let s: String = ss.into();
// or
let s = ss.to_owned();
  • String::fromstr::to_owned を呼ぶ
  • str::intoString::from を呼ぶ
  • str::to_stringString::from を呼ぶ
文字列操作が目的の変換
let ss: &str = "str";

// 文字列置換を伴う型変換
let s_replaced = ss.replace("str", "String");
// or
let s_replaced = ss.replacen("str", "String", 1);

// 繰り返しを伴う型変換
let s_repeated = ss.repeat(3);

// 大文字・小文字変換を伴う型変換
let s_ascii_lowercase = ss.to_ascii_lowercase();
// or
let s_ascii_uppercase = ss.to_ascii_uppercase();
// or
let s_uppercase = ss.to_uppercase();
// or
let s_lowercase = ss.to_lowercase();

1. 文字列スライス str を文字列 String に変換する 16 つの方法

let ss: &str = "str";

let s: String = ss.to_string();
// or
let s: String = String::from(ss);
// or
let s: String = ss.into();
// or
let s: String = ss.to_owned();
// or
use std::convert::TryFrom;
let s: String = String::try_from(ss).unwrap();
// or
use std::convert::TryInto;
let s: String = ss.try_into().unwrap();
// or
use std::str::FromStr;
let s: String = String::from_str(ss).unwrap();
// or
let s: String = ss.parse().unwrap();
// or
let s: String = String::from_utf8(ss.as_bytes().to_owned()).unwrap();

// 文字列置換を伴う型変換
let s_replaced: String = ss.replace("str", "String");
// or
let s_replaced: String = ss.replacen("str", "String", 1);

// 繰り返しを伴う型変換
let s_repeated: String = ss.repeat(3);

// 大文字・小文字変換を伴う型変換
let s_ascii_lowercase: String = ss.to_ascii_lowercase();
// or
let s_ascii_uppercase: String = ss.to_ascii_uppercase();
// or
let s_uppercase: String = ss.to_uppercase();
// or
let s_lowercase: String = ss.to_lowercase();

※説明のために変数全てで型指定をしていますが、型指定を省略できるものもあります。

1.1. UTF-8 バイト列から文字列 String に変換

str 型から変換する前に、まずは UTF-8 バイト列からの変換を確認します。

to_owned メソッドについては後述。

let ss: &str = "str";

let bytes: &[u8] = ss.as_bytes();

let bytes_owned: Vec<u8> = bytes.to_owned(); // &[u8] -> Vec<u8>

let s: String = String::from_utf8(bytes_owned).unwrap(); // Vec<u8> -> String

参考「from_utf8 - String in std::string - Rust

1.2. to_owned メソッドで借用データを異なる型で複製し所有する

Rust における to_ownedclone (クローン、複製する) を一般化した概念で、clone では &Self 型から Self 型の複製を生成するのに対し、to_owned&Self 型から Self::Owned 型の複製を生成します。

借用したデータをそのまま所有することはできないので、複製して所有します。

参考「ToOwned in std::borrow - Rust

let ss: &str = "str";

let s: String = ss.to_owned();

str 型における ToOwned トレイトの実装は以下のようになっています。

to_owned メソッドの定義
impl ToOwned for str {
    type Owned = String;
    #[inline]
    fn to_owned(&self) -> String {
        unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
    }
    // ...
}

参考「ToOwned - str - Rust

from_utf8_unchecked 関数は from_utf8 関数の安全でない版で、正しい UTF-8 バイト列かどうかを確認せずに文字列 String に変換します。

参考「from_utf8_unchecked - String in std::string - Rust

&[u8] から Vec<u8> に型変換し所有するところでも to_owned メソッドを使用します。

1.3. String::from メソッドは str::to_owned メソッドを呼ぶ

let ss: &str = "str";

let s: String = String::from(ss);

String 型は From トレイトを実装し、本記事で使用している String::from メソッドの定義は以下の通りです。

from メソッドの定義
impl From<&str> for String {
    // ...
    #[inline]
    fn from(s: &str) -> String {
        s.to_owned()
    }
}

参考「From<&'_ str> - String in std::string - Rust

1.4. String::from メソッドを呼ぶメソッド

let ss: &str = "str";

let s: String = ss.into();
// or
let s: String = ss.to_string();

From トレイトを実装する型があるとき、その逆の特性である Into トレイトが自動で実装されます。
これにより、frominto で逆の変換ができます。

Into トレイトのブランケット実装
impl<T, U> Into<U> for T
where
    U: From<T>,
{
    fn into(self) -> U {
        U::from(self)
    }
}

&str 型は Into トレイトをブランケット実装します。

into メソッドの定義 (※理論上のソースコード)
impl Into<String> for &str {
    fn into(self) -> String {
        String::from(self)
    }
}

参考「Into<U> - Into in std::convert - Rust

str 型の to_string メソッドでは String::from メソッドを呼びます。

to_string メソッドの定義
impl ToString for str {
    #[inline]
    fn to_string(&self) -> String {
        String::from(self)
    }
}

参考「ToString - str - Rust

1.5. try_from メソッドと try_into メソッド

from / into で型変換ができるということは、失敗する可能性のある型変換 try_from / try_into で型変換を試みて必ず成功するという特性を持つと考えられます。

let ss: &str = "str";

use std::convert::TryFrom;
let s: String = String::try_from(ss).unwrap();
// or
use std::convert::TryInto;
let s: String = ss.try_into().unwrap();

実際に、TryFrom トレイトと TryInto トレイトは以下のようにブランケット実装されます。

TryFrom トレイトのブランケット実装
impl<T, U> TryFrom<U> for T
where
    U: Into<T>,
{
    type Error = Infallible;

    fn try_from(value: U) -> Result<Self, Self::Error> {
        Ok(U::into(value))
    }
}
try_from メソッドの定義 (※理論上のソースコード)
impl TryFrom<&str> for String {
    type Error = Infallible;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        Ok(<&str>::into(value))
    }
}

参考「TryFrom<U> - String in std::string - Rust

TryInto トレイトのブランケット実装
impl<T, U> TryInto<U> for T
where
    U: TryFrom<T>,
{
    type Error = U::Error;

    fn try_into(self) -> Result<U, U::Error> {
        U::try_from(self)
    }
}
try_into メソッドの定義 (※理論上のソースコード)
impl TryInto<String> for &str {
    type Error = String::Error;

    fn try_into(self) -> Result<String, String::Error> {
        String::try_from(self)
    }
}

参考「TryInto in std::convert - Rust

1.6. from_str メソッドと parse メソッド

from_str / parse は文字列スライス str との変換に特化した from / into のような機能です。

let ss: &str = "str";

use std::str::FromStr;
let s: String = String::from_str(ss).unwrap();
// or
let s: String = ss.parse().unwrap();

String 型は FromStr トレイトを実装します。

impl FromStr for String {
    type Err = core::convert::Infallible;
    #[inline]
    fn from_str(s: &str) -> Result<String, Self::Err> {
        Ok(String::from(s))
    }
}

参考「FromStr - String in std::string - Rust

str::parse メソッドは文字列 str 型から FromStr トレイトを実装する型に変換します。

impl str {
    // ...
    pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
        FromStr::from_str(self)
    }
    // ...
}

参考「parse - str - Rust

1.7. 文字列操作が目的の変換

Rust における文字列操作は String 型同士でも行えますが、文字列スライス str から直接文字列操作をするメソッドがあります。

let ss: &str = "str";

// 文字列置換を伴う型変換
let s_replaced: String = ss.replace("str", "String");
// or
let s_replaced: String = ss.replacen("str", "String", 1);

// 繰り返しを伴う型変換
let s_repeated: String = ss.repeat(3);

// 大文字・小文字変換を伴う型変換
let s_ascii_lowercase: String = ss.to_ascii_lowercase();
// or
let s_ascii_uppercase: String = ss.to_ascii_uppercase();
// or
let s_uppercase: String = ss.to_uppercase();
// or
let s_lowercase: String = ss.to_lowercase();

参考「str - Rust

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3