いままでC#、C/C++のC系?でプログラムを作成してきたわけであるが、関数型の言語も学習すると良いことがある
という眉唾ものの記事を読んだ影響で純粋関数型言語Haskellもかじってみた。
そうこうしているうちにRustなる比較的新しい言語が登場していることにはうすうす感づいていた。どうせC++の延長のような言語なんだろうと少々高を括っていたのだか、どれどれ、と重い腰を上げて学習にとりかかってみると、どうもおかしい、変だ、難しい、一筋縄ではいかない言語だと痛感する。
これは!
関数型言語に近いと感じ、しかも高速に動作する。難しいかもしれないが、習得するのに値する言語と判断した。Rustを使いこなせるようになればC++もHaskellも不要になるかもしれない。(独断です)
先程、眉唾ものと書いたが記事は正しかった
Rustの出現は脅威ではあるが、それでもHaskell(関数型言語系)を学習することの重要性は変わらない。むしろRustを学ぶにおいて、事前にHaskellをやっていたことが理解を早めたといってよい。
新しい言語を学ぶには、なにより沢山のコードを書いてみるのが早道。といわけで定番?のマンデルブロ集合の画像を作成してみたわけである。
作成したコードは若干冗長であり、改善の余地は大いに存在する。
まずはなによりRustのセットアップ
すでにインストール済みの方は次のセクションに進むのだ。それ以外の方は...
Rustの公式 https://www.rust-lang.org/ja/tools/install
に沿って
Rustをインストールだ。
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
次に cargo init
コマンドを使って初期のパッケージを作成
mkdir -p rust-mandelbrot
cd rust-mandelbrot
cargo init
vscodeを使ってプロジェクトを開く
現在のところ最もRustの拡張機能が整っているIDEがvscodeなので、vscode利用を前提に進む。
code .
cargo
は自動的にgit
の設定までやってくれる。
自動で作成されたmain.rs
を試しに以下のように修正する。(コピー&ペーストでもよい)
println!("Hello, world!"); なる行が存在するが、消してしまってかまわない
use image::{ImageBuffer, Rgb, RgbImage};
use irospace::{converter::*, ColorConverterBuilder, HsvColor, RgbColor};
use itertools::Itertools;
use num::complex::Complex;
// 画像のサイズ 1000x1000
static SIZE: u32 = 1000;
fn main() {
// 複素数が使えるかのテスト
let test: num::Complex<f64> = Complex::new(0.0, 0.0);
println!("複素数 {}", test);
// 1000x1000の画像データを作成
let plot_data: Vec<u32> = plot(SIZE);
// PNG画像を作成
let mut img: ImageBuffer<image::Rgb<u8>, Vec<u8>> = RgbImage::new(SIZE, SIZE);
// HSVからRGBへの変換器を作成
let converter = ColorConverterBuilder::new().from_hsv().to_rgb().build();
// 1000x1000の x,y座標の組み合わせを作成
let grid = (0..SIZE).cartesian_product(0..SIZE);
// x,y座標に色を割り当てる
grid.for_each(|x| {
// 色を取得
let color = plot_data[(x.0 * SIZE as u32 + x.1) as usize];
// HSVの H に色を割り当てる
let color_code = HsvColor::new(color as u16, 255, 255);
// HSVからRGBへ変換
let rgb: RgbColor = converter.convert(&color_code).unwrap();
// 画像に色を割り当てる
img.put_pixel(x.0, x.1, Rgb([rgb.r(), rgb.g(), rgb.b()]));
});
// 画像を保存
img.save("out_image.png").unwrap();
}
// プロットするデータを作成
fn plot(size: u32) -> Vec<u32> {
// 360色の色を割り当てる
let ret: Vec<u32> = (0..(size * size)).map(|n| (n / size) % 360).collect();
ret
}
次に上記で利用する外部クレートをADDするため以下のコマンドを実行する。
cargo add image add irospace itertools num
必要とした外部クレートは以下
- image
- png ファイルを作成するため
- irospace
- 色空間を操作するためHSVからRGBなど
- itertools
- 直積集合を表現するため (1000x1000のグリッド作成)
- num
- 今後利用する複素数を扱うため
準備ができたらvscode
のコンソールから以下のコマンドを実行すると
out_image.png
が出来上がる。
cargo run
out_image.png
いまは虹色だが plot
関数を修正していくことで最終的に以下の画像を生成する。
次回へ