Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

文字列型変換ガイド

Rustの文字列型の変換方法をまとめました。

文字列型の種類

説明所有権
Stringヒープ上の可変文字列あり
&str文字列スライス(参照)なし
&StringStringへの参照なし
&'static str静的な文字列リテラルなし

変換早見表

                    .to_string()
              ┌────────────────────┐
              │                    ▼
           &str ◄──────────────── String
              │    &s, .as_str()    │
              │                     │
              │                     │
    .to_owned()                  .clone()
              │                     │
              ▼                     ▼
           String               String

&str → String

#![allow(unused)]
fn main() {
// 方法1: to_string()
let s: &str = "hello";
let string: String = s.to_string();

// 方法2: to_owned()
let string: String = s.to_owned();

// 方法3: String::from()
let string: String = String::from(s);

// 方法4: into()
let string: String = s.into();
}

どれを使うべき?

  • to_string(): 最も一般的
  • to_owned(): 「所有権を得る」という意図が明確
  • String::from(): 型変換であることが明確
  • into(): ジェネリクスで便利

String → &str

#![allow(unused)]
fn main() {
let s: String = String::from("hello");

// 方法1: &演算子(自動deref)
let slice: &str = &s;

// 方法2: as_str()
let slice: &str = s.as_str();

// 方法3: スライス構文
let slice: &str = &s[..];
}

どれを使うべき?

  • &s: 最もシンプル
  • as_str(): 意図が明確

数値 → String

#![allow(unused)]
fn main() {
// 方法1: to_string()
let n: i32 = 42;
let s: String = n.to_string();

// 方法2: format!マクロ
let s: String = format!("{}", n);

// フォーマット指定
let hex: String = format!("{:x}", 255);   // "ff"
let padded: String = format!("{:05}", 42); // "00042"
}

String → 数値

#![allow(unused)]
fn main() {
let s: &str = "42";

// 方法1: parse()
let n: i32 = s.parse().unwrap();

// 方法2: parse()(型を明示)
let n = s.parse::<i32>().unwrap();

// エラーハンドリング
match s.parse::<i32>() {
    Ok(n) => println!("数値: {}", n),
    Err(e) => println!("パースエラー: {}", e),
}
}

char → String

#![allow(unused)]
fn main() {
let c: char = 'A';

// 方法1: to_string()
let s: String = c.to_string();

// 方法2: String::from()
let s: String = String::from(c);

// 方法3: format!
let s: String = format!("{}", c);
}

String → char

#![allow(unused)]
fn main() {
let s: String = String::from("A");

// 最初の文字を取得
let c: char = s.chars().next().unwrap();

// すべての文字をイテレート
for c in s.chars() {
    println!("{}", c);
}
}

Vec ↔ String

#![allow(unused)]
fn main() {
// String → Vec<u8>
let s = String::from("hello");
let bytes: Vec<u8> = s.into_bytes();

// Vec<u8> → String(UTF-8として解釈)
let bytes = vec![104, 101, 108, 108, 111];  // "hello"
let s: String = String::from_utf8(bytes).unwrap();

// 失敗する可能性がある場合
match String::from_utf8(bytes) {
    Ok(s) => println!("{}", s),
    Err(e) => println!("Invalid UTF-8: {}", e),
}

// lossy変換(無効なバイトは置換)
let s = String::from_utf8_lossy(&bytes);
}

&[u8] → &str

#![allow(unused)]
fn main() {
let bytes: &[u8] = b"hello";

// UTF-8として解釈
let s: &str = std::str::from_utf8(bytes).unwrap();

// または
match std::str::from_utf8(bytes) {
    Ok(s) => println!("{}", s),
    Err(e) => println!("Invalid UTF-8: {}", e),
}
}

PathBuf ↔ String

#![allow(unused)]
fn main() {
use std::path::PathBuf;

// String → PathBuf
let s = String::from("/path/to/file");
let path = PathBuf::from(&s);

// PathBuf → String
let path = PathBuf::from("/path/to/file");
let s: String = path.to_string_lossy().into_owned();

// PathBuf → &str(失敗する可能性あり)
if let Some(s) = path.to_str() {
    println!("{}", s);
}
}

OsString ↔ String

#![allow(unused)]
fn main() {
use std::ffi::OsString;

// String → OsString
let s = String::from("hello");
let os_string = OsString::from(&s);

// OsString → String
let os_string = OsString::from("hello");
match os_string.into_string() {
    Ok(s) => println!("{}", s),
    Err(os_string) => println!("Invalid UTF-8"),
}

// lossy変換
let s = os_string.to_string_lossy().into_owned();
}

CString ↔ String(FFI用)

#![allow(unused)]
fn main() {
use std::ffi::{CString, CStr};

// String → CString
let s = String::from("hello");
let c_string = CString::new(s).unwrap();  // NULLバイトがあるとエラー

// CString → String
let c_string = CString::new("hello").unwrap();
let s: String = c_string.into_string().unwrap();

// &CStr → &str
let c_str: &CStr = c_string.as_c_str();
let s: &str = c_str.to_str().unwrap();
}

よくある変換パターン

関数の引数として

#![allow(unused)]
fn main() {
// &strを受け取る(推奨)
fn process(s: &str) {
    // String も &str も渡せる
}

// 使用
process("literal");           // &str
process(&String::from("s"));  // &String → &str(自動deref)
process(String::from("s").as_str()); // 明示的
}

構造体のフィールドとして

#![allow(unused)]
fn main() {
// 所有権が必要な場合
struct User {
    name: String,  // 所有する
}

// 参照でよい場合(ライフタイム必要)
struct UserRef<'a> {
    name: &'a str,
}
}

戻り値として

#![allow(unused)]
fn main() {
// 新しい文字列を作る場合
fn create_greeting(name: &str) -> String {
    format!("Hello, {}!", name)
}

// 入力の一部を返す場合(ライフタイム必要)
fn first_word(s: &str) -> &str {
    &s[..s.find(' ').unwrap_or(s.len())]
}
}

まとめ

変換方法
&strString.to_string(), .to_owned()
String&str&s, .as_str()
数値 → String.to_string(), format!()
String → 数値.parse()
Vec<u8>StringString::from_utf8()
StringVec<u8>.into_bytes()

基本方針:

  • 関数の引数は &str で受け取る(柔軟性)
  • 所有権が必要なら String を使う
  • 変換が必要な時は目的に合った方法を選ぶ