検索
連載

なぜわざわざ学習コストを払ってまでRustを採用するのか? Webエンジニア目線でRustを考察WebエンジニアからみたRust(1)

Web開発者としての興味、関心に基づきRustを端的に紹介し、その強みや弱みについて理解を深める本連載。第1回では、Rustを採用するモチベーションとは何かを整理、考察します。

Share
Tweet
LINE
Hatena

Rustへの関心の高まり

 近年、プログラミング言語「Rust」に関する重要なニュースを多く見るようになりました。例えば以下のような記事です。

Androidの開発へ「Rust」を導入、なぜなのか

Microsoft、「Rust for Windows v0.9」を公開

実装言語を「Go」から「Rust」に変更、ゲーマー向けチャットアプリ「Discord」の課題とは

 これらの記事が指し示すことは、いわゆる「GAFAM」(Google、Amazon.com、Facebook、Apple、Microsoft)と呼ばれる米国主要IT企業および先進的なWebベンチャー企業がプロダクションユースとしてRustを採用し始めており、さらに継続的投資意欲があることを示していると考えられます。他にもRustの勢いを示すものとして以下のような記事があります。

「Rust」はなぜ人気があるのか、Stack Overflowがユーザーのコメントを紹介

 Stack Overflowにおける最も愛される言語の1位にRustが君臨しています。2016年から2020年まで5年連続でRustが1位をキープし続け、さらには2020年の結果では非常に勢いのある言語である2位のTypeScriptに19ポイントという大差をつけて1位を獲得しており、エンジニアコミュニティーにおいても極めて勢いがある言語であるように感じられます。

 これらは単なる一過性のブームなのでしょうか。手慣れた既存言語ではなく、新しい言語であるRustを利用、学習するのはなぜでしょうか。第1回ではRustを採用するモチベーションとは何かを整理、考察します。

RustとC/C++

 Rustはその開発のいきさつからして、C/C++からの移行が意識されています。Rustが出現するまでは、C/C++はハイパフォーマンス(最速、最高効率)なアプリケーションを開発するならば避けて通れない言語だとされてきました。一方でC/C++では、言語規格に動作の定義がない命令を記述することができてしまいます。その命令の結果生じる動作のことを、未定義動作と呼びます。未定義動作を引き起こす命令の典型例としては以下のようなものがあります。

  1. すでに解放されているメモリ領域を参照する(use after free)
  2. すでに解放されているメモリ領域をさらにメモリ解放する(double free)
  3. 無効なメモリ領域を指しているポインタ(ダングリングポインタ)を参照解決する
  4. 配列の範囲外アクセス
  5. 複数スレッドによるあるメモリの同時参照・更新(データ競合) etc.

 未定義動作の典型例は(厳密には予測不能ですが例えば)以下のようなものがあります。

  1. 本来アクセスできないデータを参照・更新できてしまう(不正アクセス)
  2. OSのメモリ保護機構によりメモリの不正アクセスを検出しプログラムが停止する(segmentation fault) etc.
// deref_null_pointer.c
#include <stddef.h>
int main(void)
{
  int *null_pointer = NULL;
  int value = *null_pointer; // 未定義動作発生
}
【未定義動作を起こす極めて単純なCのコード】このコードの問題は明白ですが、現実の問題はここまで簡単ではないはずです

【Cのコードの実行例】この実行ではOSのメモリ保護機構によりsegmentation faultとなりましたが、いつでもこの結果になるとは限りません
// deref_null_pointer.rs
fn main() {
    let p: *const i32 = std::ptr::null(); // null pointerそのものは安全である
    unsafe { // unsafeで囲まないとコンパイルエラー
        println!("{}", *p); // 未定義動作発生
    }
}
【未定義動作を起こすRustのコード】unsafeを使うとRustコンパイラの安全性保証から外れてしまう一方、C同等の自由度を獲得できます

 未定義動作を引き起こすプログラムは安全とは言えません。例えば、セキュリティ問題や障害を引き起こす可能性があります。未定義動作が生じないことをC/C++コンパイラは(警告は出せますが)保証しないので、プログラマーがコードを確認し保証する必要があります。未定義動作は、コンパイラによる最適化などにより予期せぬ振る舞いや非決定論的な振る舞いを生じることも多くデバッグも困難なものになりがちです。言語仕様に精通したプログラマーの尽力による問題解決が必要になります。

 Rustは、unsafeという言語機能を用いない限り未定義動作を引き起こし得る命令を記述しようとしてもコンパイル時または実行時エラー(パニック)になります。もしパニックとなったときでも決定論的に振る舞うのでデバッグがしやすく、なおかつC/C++に比肩するパフォーマンスを同時に有しています。

※この記事では上述の「未定義動作を引き起こす命令」のうち1、2、3、4のような命令から保護されている、あるいは適切な動作が規定されていることをメモリ安全、5のような命令から保護されていることをスレッド安全と呼ぶことにします。

Web開発者の視点から見たRust

Copyright © ITmedia, Inc. All Rights Reserved.

ページトップに戻る