とにかく書く

日々の雑感や知り得たことを、とにかく書いています

おっさんの挑戦(画像ビューア作成) 004

おっさんになると急激に理解力や記憶力が低下したことを感じる。

法月綸太郎氏の「頼子のために」を読んだ。
法月綸太郎氏が25歳の時、1987年初版刊行。もともとは大学生時代の中編に肉付けしたそうだ。最後がとても面白かった。
若い。羨ましい。すごい。

でもちょっと古い。体型の表現に「電話ボックス」、カセットテープの再生に「オートリバース」は、もう年齢を必要とする。
おっさんはついニヤッと気持ちの悪い笑みを浮かべてしまう。

前途洋々の若人のためにオートリバースについて書くと、
カセットテープは、CDなどと違って、任意の場所から再生させるには、磁器テープを巻いて移動させなければならない。
オートリバースは、最後まで再生したカセットテープを自動的に巻き戻して、最初から再生させる機能。
巻き戻すっていうのは、磁気テープを再生時とは逆方向に巻くことを指す。

だけど、この「オートリバース」って表現は、機械の機能についての呼び名であって、聴衆向けの表現ではない。
聴衆はテープの最初から再生するのだから、自動再生やリピート再生だよね。
こうした技術者寄りの表現も、時代ならではという気がする。

最近は、表現はずいぶん使い手寄りになったなぁと思う。
一方高機能すぎて、おっさんには使いこなせない。かちこち頭のおっさんには、新しいことに順応するのは難しいのだ。

Rust も豊富な機能を取り揃えていて、しかも cargo で楽に入手できる。
だけど高機能すぎて、なかなか使いこなせない。なんでまたコンパイルエラーなんだろう…。

std::path::Path を使って、表示する画像をコマンドライン引数で受け取るようにした。
複数の指定やディレクトリの指定もできた。
Next ボタンを追加して、指定した画像ファイルを順番に表示するようにした。
だけど、たったこれだけを実装するのに半日は費やした。

なにより所有権と、String, &Str などの違いがよくわかっていない。
概念は理解しているのだけど、結局所有権にまつわる問題を回避するために、ひたすら clone() している。
もっとそれぞれの動きを考慮して、これは参照で良い、と決めれば良いのだけど、自分で書いたコードのくせに追っていくのが難しい。
ともあれ、自分の能力の限界に応じて少しずつ進めていくしかない。

指定したファイル、ディレクトリ内のファイル名を Vec で返す file_or_files_in_dir 関数だけ載せます。
シンボリックリンクをたどることはしていない。参照先のサブディレクトリに自分がいると循環してしまうから。

use std::ffi::OsString;
use std::path::Path;

#[derive(Debug, Clone)] // derive Debug, Clone trait
struct Images {
    files: Vec<OsString>,
    index: usize,
}

impl Images {
    fn new(args: Vec<String>) -> Result<Self, &'static str> {
        let mut instance = Images {
            files: Vec::new(),
            index: 0,
        };
        if args.len() < 2 {
            return Err("No files are specified");
        }
        // for each argument,
        for arg in &args {
            for f in instance.file_or_files_in_dir(&OsString::from(arg), true) {
                instance.files.push(f);
            }
        }
        instance.files.remove(0);
        println!("{:?}", instance.files);
        Ok(instance)
    }

    // this function returns path strings of the spcified directory.
    fn file_or_files_in_dir(&mut self, path_str: &OsString, recursive: bool) -> Vec<OsString> {
        let mut files: Vec<OsString> = Vec::new();
	let path = Path::new(path_str);
		
	if path.is_file() {
	    files.push(path_str.clone());
        } else if path.is_dir() {
            for child in path.read_dir().expect("read_dir call failed") {
                let child = child.unwrap();
                if recursive {
                    // a child directory is also expanded and pushed
                    for f in self.file_or_files_in_dir(&child.path().into_os_string(), recursive) {
                        files.push(f);
                    }
                } else {
                    // only file is pushed, dir and symlink are skipped
                    if child.path().is_file() {
                        files.push(child.path().into_os_string()); //file_name());
                    }
                }
            }
	} else { // SYMLINK
	     // do nothing. we have never implement for circular reference
	}
	files
    }
}