プログラマーという職業には、35歳定年説というのがある。
この時点で、非難轟々の方々もおられようが、私も35歳ころから、だんだん if 文を書くことに苦痛を感じ始めた。学生時代から打ち込んでいた分野で壁にぶつかって、深夜にジョニーウォーカー黒ラベルを一人傾けて、妙に鬱々としていた。ただのアル中だった。
そんなこんなあって、仕事が変わった。もはや前線兵士ではない。ジョニ黒もかつては高級酒だったが、いまではしがないサラリーマンでも買えてしまう。私も同じ。あぁ愛すべきジョニ黒。
新しい仕事では、画像をよく見る。最近の携帯電話は、PCで閲覧するには解像度が大きすぎるので、サイズを変更したい。おじさんはそんなに大きくなくていい。控えめでいい。だけど tiff も見たい。おじさんは欲張り。全部キーボードで操作したい。マウスとか何だか知らない画面タッチとか、口に出すのがちょっと恥ずかしい「スワイプ」とか、そういうのいらない。キーボードでいい。
ボケないためには、新しいことに挑戦するといいらしい。頭への刺激がボケ防止につながるとか。体を動かしながら(踊りながら)考えると(コーディングすると)なお一層効果がある。
そんなわけで、おじさんのはじめての Rust で画像ビューアーを作ってみることにした。
ここ2週間で The Book (第二版、日本語訳) の9章(エラー処理)まで読み進めた。1日1章。遅いけど、おじさんだし仕方ないね。
この時点でちょっと調べてみると、画像はimage クレートが使えそう。GUI は、ちょこちょこ見比べて iced が良さそう。
まず iced のドキュメント を参照にして、GUI 画面を出そうと思う。なにはともあれ、文字よりウィンドウが出たほうがババーンって感じで楽しい。
iced は、Elm の構造を参照にしているとのこと。Elm は 2012 年に修論として設計されたそうだ。最近過ぎて全然知らない。
ともあれ、ドキュメントをもとに根幹の概念を理解した。わかりやすい。
- State : アプリケーションの状態
- Messages : イベント(マウスクリックやキー押下など)
- View Logic : State をどう画面表示するか
- Update Logic : Messages に対する処理
で、ドキュメントにあるコード(カウンタ:ボタンを押すと画面の数字が増える)を実装した。
$ cargo run っと。
エラーが出た。
なんかエラーを見ると、確かにColumn型を返しているのに、その処置が正しくないようだ。よーわからんままいじっても、エラーが増えてよーわからん。そもそもクレートってなんだ?
クレートって、The Book のどこに載っていたかな?と見ると、10章じゃねーか。まだ9章までしか読んでねーよ。
まず10章を読みます。おっさんだししょうがないね。ジョニ黒おいしいね。
とりあえずエラーが出ているコード。よーわからんままいじった状態。
use iced::{button, executor, Application, Button, Column, Command, Settings, Text}; fn main() { Counter::run(Settings::default()) } // State - the state of my application #[derive(Debug, Clone, Copy)] struct Counter { // The counter value value: i32, // The local state of the one buttons increment_button: button::State, } // Message - event that we care about #[derive(Debug, Clone, Copy)] pub enum Message { IncrementPressed, } impl Application for Counter { // Use default type Executor = executor::Default; type Message = Message; type Flags = (); fn new(_flags: ()) -> (Counter, Command<Message>) { (Counter::default(), Command::none()) } // View Logic fn view(&mut self) -> Counter<Message> { // Use a column: a simple vertical layout Column::new() .push( // The increment button. // The event IncrementPressed is launched when it is pressed Button::new(&mut self.increment_button, Text::new("+")) .on_press(Message::IncrementPressed), ) .push( // The message Text::new(self.value.to_string()).size(50), ) } // Update logic: connect events to functions fn update(&mut self, message: Message) { match message { Message::IncrementPressed => { self.value += 1; } } } fn title(&self) -> String { String::from("kilo") } }