2022年11月06日21時21分 / 提供:マイナビニュース
Rustは実行効率や安全性を重視したプログラムが作れる人気のプログラミング言語です。それでも習得が難しいと言われることもあります。本連載ではいろいろな有名アルゴリズムを解くことでRustに慣れることを目的にしています。今回は、シーザー暗号を解いてみましょう。
○Rustは難しい言語か?
RustはC/C++言語並みに実行効率が良いのですが、安全性を重視した言語になっています。最近では、ブラウザ上でもRustを快適に動かすことができるようになっており、ますます多くのプログラマーがRustを学んでいます。
とは言え、PythonやJavaScript、Rubyなどのスクリプト言語と比べたら難しいと感じる場面もあります。
まず、Rustはコンパイル言語であり、逐次実行するスクリプト言語とは大きく異なっています。また、スクリプト言語よりもデータ型に厳密です。加えて、スクリプト言語ではあまり意識することがなかった、メモリの扱いについても考える必要があります。
それでも、C/C++言語と比べて難しいかと言われると、筆者の個人的な感想で言えば、それほど難しくないのではと思います。C/C++ではメモリの確保と解放はプログラマーの責任で処理しなくてはなりません。メモリ管理の失敗によりアプリがクラッシュしたり、脆弱性の原因になったりします。
これに対して、Rustでは所有権システムにより、コンパイラにより自動で確保と解放が行われるため、そのため、それほど神経質にメモリ管理を意識する必要はありません。もちろん、Rustのメモリ管理の肝である所有権システムについては学ぶ必要がありますが、C/C++のポインタの概念と同じく、慣れの問題とも言えるでしょう。また、Rustの言語文法は新しい言語だけあって整然としており、複雑怪奇という訳ではありません。
どんな言語でも、最初はその言語について習熟するのに時間がかかるのは仕方のないことです。実際のところ、PythonやJavaScript、Rubyなどのスクリプト言語よりは難しいけど、C/C++よりは難しくないというところでしょう。本連載では定番アルゴリズムをRustで解いていくので、それらを眺めることで自然とRustに慣れることができます。
○シーザー暗号とは?
連載2回目の今回は、Rustで『シーザー暗号(英語:Caesar cipher)』を実装してみます。このシーザー暗号は、最もシンプルで広く知られた暗号の一つです。古代ローマの軍事的指導者ガイウス・ユリウス・カエサルが使用したことで有名な暗号です。カエサルの英語読みがシーザーなので、シーザー暗号と呼ばれます。
その仕組みですが、アルファベットを辞書順で3文字ずらすことで作成する暗号です。次の図のように、[A]ならばB,C,Dと3文字ずらして[D]に、同様に、[B]ならば[E]、[C]ならば[F]とずらすことで暗号を作ります。
例えば「CAFE」ならば、シーザー暗号で3文字右にずらして「FDIH」となります。逆に、暗号文「FDIH」を復号化するには、3文字左に文字をずらします。もちろん、同じ要領で任意の文字ずらす(シフトする)ことで、異なる暗号文を作ることもできます。
○Rustで実装してみよう
それでは、このシーザー暗号をRustで実装してみましょう。Rustで実装する場合も、他の言語と同様に1文字ずつ暗号化したい文字を取り出して、指定文字数だけシフトさせて結果文字列に追加していくという処理を行います。
以下がシーザー暗号のプログラムです。以下を「caesar.rs」という名前で保存しましょう。
fn main() {
// 暗号化と復号化 --- (*1)
let text = "I LOVE YOU.";
let enc_text = rotate(&text, 3); // 暗号化
let dec_text = rotate(&enc_text, -3); // 復号化
println!("文字列: {}", text);
println!("暗号化: {}", enc_text);
println!("復号化: {}", dec_text);
}
// シーザー暗号を作成する関数 --- (*2)
fn rotate(text: &str, shift: i16) -> String {
// 変換結果を保存する文字列オブジェクト --- (*3)
let mut result = String::new();
// 1文字ずつ繰り返す --- (*4)
for ch in text.chars() {
// 小文字は大文字に変換 --- (*5)
let ch = if ch.is_lowercase() { ch.to_ascii_uppercase() } else { ch };
// 大文字のときのシフト処理 --- (*6)
if 'A'