全2534文字
PR

所有権は貸し出せる!「借用」を使いこなそう

 所有権に関するコンパイルエラーはどのように解決すればいいのだろうか。Rustでメモリーを正しく使う方法を学んでいこう。

値を複製すれば一応解決できるが…

 手段の1つとしてまず考えられるのは「値の複製」だ。

 複製を可能にする「Clone」というトレイトを実装すると、構造体全体の複製が可能になる。これを利用してプログラムを書き直すことは可能だ。複製済みの変数をprint_meta_info関数に渡すようにすれば、複製後の値の所有権が`print_meta_info関数に移るだけで済む。

#[derive(Clone)]
struct Article {
    title: String,
    description: String,
    author: String,
    body: Vec<u8>,
}

fn print_meta_info(article: Article) {
    println!("title: {}, author: {}", article.title, article.author);
    println!("description: {}", article.description);
}

fn display_body(article: Article) {
    println!("{}", std::str::from_utf8(&article.body).unwrap());
}

fn main() {
    let article = Article {
        title: "Rustで作るWebアプリケーション".to_string(),
        description: "Rustで実際にWebアプリケーションを作りながら、Rustの魅力を伝える記事です。"
            .to_string(),
        author: "Yuki Toyoda".to_string(),
        body: "ここに記事の内容が入ります。以下続く。".as_bytes().to_vec(),
    };

    // articleの値が複製され、複製後の値の所有権が関数に移る
    print_meta_info(article.clone());

    // この時点でまだarticleの値の所有権があるためコンパイルエラーにならない
    display_body(article);
}

 「#[derive(Clone)]」という記述は、「[#derive]アトリビュート」を使って型に対して特定のトレイトを実装するものだ。ここではCloneトレイトを指定することで、構造体の複製を可能にしている。

 しかし、この方法には大きな問題がある。複製は一般にコストが大きい作業であることだ。特にデータサイズの大きな構造体を複製すると、それだけでメモリーを大きく圧迫する。この問題の解決法としては、あまりよくない実装だ。