初めて"git push -f origin master"した。
gitへのForceとかいう不吉なことをした。
rustのコマンドを書き始めたので、gitへfirst commitしようと思った。
エラー
gitのリモートのmasterブランチが先端にないので、ローカルのほうがブランチの先にあることになり、マージできないということらしい。よくわからない。
hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
解決策
普通はこれをすればいいらしい。
git pull origin master git push origin master
しかし
なんかよくわからないがmergeを拒否された。
git pull origin master From https://github.com/psato/tree-cd * branch master -> FETCH_HEAD fatal: refusing to merge unrelated histories
今回の解決策
gitにforceした。
git push -f origin master
感想
今回は最初のコミットだったので、壊れる内容もなかったからforceした。 しかし、重要なプロジェクトで起きたらどうしようか。。。
参考文献
『すべての知識を20字でまとめる。紙一枚独学法』の感想メモ
20字でまとめると
20字で教えられるようにインプットする方法(21字)
紙のフォーマット画像
[evernote:22a7eefaf81a1302138301b1aea7f604 アップロード中] [evernote:8c8e2b8fb78342e29db9d22de25dcd9b アップロード中] [evernote:2b5e5593676702e682881854aeade9ee アップロード中]
学んだことを忘れないために重要なのは
- 目的の明確化
- 思考整理
- 端的な要約
メモ
- 勉強する前に目的を紙に書いて、チラミしながら読む
- 人に説明できることが理解の達成条件
- 3つの疑問を自らに問いかけ、それを満たせるとき理解したと胸をはる
- What,Why,How
- 教養は自信の拠り所になる
- 消費型学習ではなく、投資型学習へ
- アウトプットできるとは教えられるということ
- Howは抽象的ではなく具体的な動作で書く
やり方
- 1回読んだら10分で16個程度キーワードを紙に抜き出す
- キーワード同士を赤ペンで関係を書き込み、重要なものを整理する
- 目的を達成するために、内容を3つの問(why,what,how)に落とし込む
- 20字で要約する
- 赤ペンで修正する
他者貢献
- 働く=傍を楽にする
- 「あなたはなぜ仕事をしているのか」
- 「あなたが最近仕事で困っていることは」
- 「あなたが最近熱心に学んでいることは」
- 他者貢献の考えが普段からあれば、この問への回答に他者が出てくるはず。
- 他者を楽にするという考え方で、コントリビューション学習法を作ってみると仕事がうまくいく
[evernote:22a7eefaf81a1302138301b1aea7f604 アップロード中] [evernote:8c8e2b8fb78342e29db9d22de25dcd9b アップロード中]
[evernote:2b5e5593676702e682881854aeade9ee アップロード中]
[evernote:642fc7a8d10ebf0f2b70d0e14435b23a アップロード中]
bit全探索
abc173
bit全探索とは
True Falseの2値で表せるような事象の組み合わせを探索したいときに、便利な探索方法
pythonでは
1<< HOGE
23 を表したいとき、
1bitを3つ左シフトさせること
探索で使いたいのでrange(1<<HOGE)
で使われる
2(100) == 10(8)
1か0かチェックするには
01というintで管理しているので、2で割ったあまりが1か見る。
productライブラリ
from itertools import product for a in product([True, False], repeat=H): for b in product([True, False], repeat=W):
問題
回答
H, W, K = map(int, input().split()) c = [input() for _ in range(H)] result = 0 for rows in range(1 << H): for cols in range(1 << W): black = 0 # bitが1になっているか2重ループで探索 # 赤なら黒ではないからcontinue # それ意外ならblackカウンタインクリメント for i in range(H): if (rows >> i) % 2 == 1: continue for j in range(W): if (cols >> j) % 2 == 1: continue if c[i][j] == "#": black += 1 if black == K: # ループのなかで条件に合う場合をカウントする result += 1 print(result)
ソフトウェアシステム論 (exaを読む 実践編)
要旨
メモ
講義を忘れないためにとりあえずメモ
Result<T,E>型
Result<,>ってなに
* _
はなんでもいいときに使う?
Result<T,E>はいつ使う * エラー処理のための戻り値につかう。 * Rustは例外がない。 * Result<>かpanic!を使う。 * 回復可能なResult<> * 終了させるpanic!
?演算子(?後置演算子)
- エラー委譲の省略形の書き方 実行時、エラーを想定して予めmatchで条件分岐などを書きたくない場合に用いる。 失敗すると、単に関数の実行から抜ける。
PathBuf
- パスを扱うためのライブラリ
path.push(ファイル)でパスが
path/ファイル
の形で追加される。Vec<String>
https://doc.rust-lang.org/nightly/std/convert/trait.From.html https://doc.rust-jp.rs/rust-by-example-ja/std_misc/path.html 参考
cloneをなぜするのか
他の言語のdeepコピーに相当する。 同じオブジェクトに別の名前を束縛するのではなく、新たにコピーを作る。
今回exaでcloneをする理由は所有権かライフタイムの問題からだと思われる。 参考
exaデバッグ実行
main.rs
11行目
configure_logger();
- logを取るメソッド
13行目
let args: Vec<OsString> = args_os().skip(1).collect();
- args:OsStringを持つ配列
- args_os().skip(1)がイテレータを返す
- collect()がイテレータを配列にまとめる args_os().skip(1).collect():コマンド実行の引数をコマンドそれ自体をスキップしてそれ以降の引数を配列'args'として得る。
14行目
match Exa::from_args(args.iter(), &mut stdout()) {
main.rs
2行目にuse exa::Exa
とあり、外部ライブラリファイルexa.rs
のExaメソッドをインポートしている- match式で
from_argsメソッド
に対し引数args.iter()
,stdout()
を渡す args.iter()
は配列argsからイテレータを作るstdout()
は標準出力へのハンドラを作る
from_args()
exa.rs 86行目
pub fn from_args<I>(args: I, writer: &'w mut W) -> Result<Exa<'args, 'w, W>, Misfire> where I: Iterator<Item=&'args OsString> { Options::parse(args, &LiveVars).map(move |(options, mut args)| { debug!("Dir action from arguments: {:#?}", options.dir_action); debug!("Filter from arguments: {:#?}", options.filter); debug!("View from arguments: {:#?}", options.view.mode); // List the current directory by default, like ls. // This has to be done here, otherwise git_options won’t see it. if args.is_empty() { args = vec![ OsStr::new(".") ]; } let git = git_options(&options, &args); let ignore = ignore_cache(&options); Exa { options, writer, args, git, ignore } }) }
これは途中でmap()の中に入るので注意
parse()
イテレータを解析してOptions構造体とfree filenameの配列を作成するLiveVars
はThe “real” environment variables type.
,just calling "var_os"
環境変数?よくわからない。move
するのはRustの変数のライフタイムが遅延評価のmapのクロージャの中でwriterを使うから?- 戻り値は構造体Exa
exa.rs 93行目
if args.is_empty() { args = vec![ OsStr::new(".") ]; }
- 引数がないならカレントディレクトリ
.
を引数にする
15行目
Ok(mut exa)
- match式が問題なく実行された場合の処理が書かれている
16行目
match exa.run(){
exa.run()
- 実際にファイルパスを取得する
exa.rs 115行目 run()
for file_path in &self.args { match File::from_args(PathBuf::from(file_path), None, None) { Err(e) => { exit_status = 2; writeln!(stderr(), "{:?}: {}", file_path, e)?; } Ok(f) => { if f.points_to_directory() && !self.options.dir_action.treat_dirs_as_files() { match f.to_dir() { Ok(d) => dirs.push(d), Err(e) => writeln!(stderr(), "{:?}: {}", file_path, e)?, } } else { files.push(f); } } } }
- exa.run()が成功すればexit
失敗したらエラーを吐いて終わり
File::from_args()の戻り値
File { path, parent_dir, metadata, ext, name, is_all_all }
- from_args()で親ディレクトリやファイル名を変数pathから得る
- Rustの&strとStirngの関係がPathとPathBufの関係と対応しているらしい。
An owned, mutable path (akin to String). This type provides methods like push and set_extension that mutate the path in place. It also implements Deref to Path, meaning that all methods on Path slices are available on PathBuf values as well. More details about the overall approach can be found in the module documentation.
#![allow(unused)] fn main() { use std::path::PathBuf; let path = PathBuf::from(r"C:\windows\system32.dll"); println!("{:?}",path) } >>> "C:\\windows\\system32.dll"
- &strは文字列スライスで参照のみ
- Stringは文字列のベクタ
- Pathのドキュメントを見るとpush,popはなかった。PathBufの方にあった。
- Pathを追加したり、削ったりという変更を加えるときはPathBufに入れるようだ。
filename()
file.rs 105行目
/// A file’s name is derived from its string. This needs to handle directories /// such as `/` or `..`, which have no `file_name` component. So instead, just /// use the last component as the name. pub fn filename(path: &Path) -> String { if let Some(back) = path.components().next_back() { back.as_os_str().to_string_lossy().to_string() } else { // use the path as fallback error!("Path {:?} has no last component", path); path.display().to_string() } }
- pathを正規化して後ろから(右から)ファイル名を返すメソッド
components()
配列じゃないものをイテレータにするnext_bask()
イテレータの後ろから要素を得るas_os_str()
PashをOsStr
形式に変換しファイル名に切り分けるto_string_lossy
無効なUnicodeが入っていたら、U+FFFD REPLACEMENT CHARACTER (�)に変換する 戻り値はCow型(A clone-on-write smart pointer.スマートポインタってなに?Rustのポインタ型)to_string()
String型に変換する
pathをクローンするのは、色々他にも作業があるから。
file.rs 35行目 * なぜpathをクローンするの?
ファイル名が抽出されていても、ファイルの絶対位置を調べたり (コンパイルされたファイルの検索など)、元のパスを使ったり (シンボリックリンクに続く) する操作があるため、パスを保持しておく必要があります。
read_dir()は何をして何を返すのか
dirs.rs 34行目
pub fn read_dir(path: PathBuf) -> IOResult<Dir> { info!("Reading directory {:?}", &path); let contents = fs::read_dir(&path)? .map(|result| result.map(|entry| entry.path())) .collect::<Result<_, _>>()?; println!("{:?}", contents); Ok(Dir { contents, path }) }
- read_dir()は何を返しているの?
read_dir()の戻り値は以下のような感じで変化する
read_dir()
->Result<ReadDir>
read_dir()?
->ReadDir
イテレータ
ReadDir
はResult<DirEntry>
を要素に持つイテレータ
2重mapはなにをしているの? 1回目map イテレータ
ReadDir
の各要素Result<DirEntry>
に対して 2回目mapResul<DirEntry>
の要素DirEntryに対してpath()
entry.path()
はDirEntryをpath型に変換する処理
#![allow(unused)] use std::fs; fn main() -> std::io::Result<()> { for entry in fs::read_dir(".")? { let dir = entry?; println!("{:?}", dir); println!("{:?}", dir.path()); } Ok(()) }
DirEntry("./.bash_logout") "./.bash_logout"
Playgrougndで実行する%5D%0Ause%20std%3A%3Afs%3B%0A%0Afn%20main()%20-%3E%20std%3A%3Aio%3A%3AResult%3C()%3E%20%7B%0A%20%20%20%20for%20entry%20in%20fs%3A%3Aread_dir(%22.%22)%3F%20%7B%0A%20%20%20%20%20%20%20%20let%20dir%20%3D%20entry%3F%3B%0A%20%20%20%20%20%20%20%20println!(%22%7B%3A%3F%7D%22%2C%20dir.path())%3B%0A%20%20%20%20%7D%0A%20%20%20%20Ok(())%0A%7D&edition=2018)
- contests変数に束縛するときの処理が分かりづらい。
- DirEntry公式ドキュメントがわかりやすかった。read_dir()はReadDir型を返すらしいが、DirEntryの例文がよりわかりやすかった。2重mapがないため。
run()の戻り値
exa.rs 144行目
self.print_dirs(dirs, no_files, is_only_dir, exit_status)
17行目
Ok(exit_status) => exit(exit_status),
- exa.run()が成功したのでexitする
- exa.run()の戻り値はfilename()
参考文献
PathBuf関係
- Rustメモ
- Rust 初心者が自動型変換や型変換関係のトレイトを自信を持って扱えるようになるための型変換まとめ 8 パターン
- Rust &strとStringを理解しようと思ったらsliceやmutを理解できてないことに気づいた話
- https://doc.rust-lang.org/std/path/struct.Path.html
- https://doc.rust-lang.org/nightly/std/path/struct.PathBuf.html
- rust playground%5D%0Afn%20main()%20%7B%0Ause%20std%3A%3Apath%3A%3APathBuf%3B%0A%0Alet%20path%20%3D%20PathBuf%3A%3Afrom(r%22C%3A%5Cwindows%5Csystem32.dll%22)%3B%0A%7D&edition=2018)
- https://keens.github.io/blog/2015/11/14/rustdechiisanatsu_ruwotsukuttemiru/
Rustのファイルシステムコールのコーディング例
map move関係
c言語でls
WordCount
実際に作ってみて
最近CLItoolを読んだり写経したりするにつれて(といってもgrep,wc,lsだけ)、RustのCLIのやってることは大なり小なり違ってもライブラリや引数の扱い方など基本的な所は一緒だなあと思います。
- wcは引数を読み込み、引数の指定するファイルを読み込みます。それをバッファにいれてパースして、カウントして、表示する。
- lsは引数を読み込み、引数の指定するディレクトリを読み込み、要素をバッファにいれて、それを表示する。
- grepは引数を読み込み、引数の指定するファイルを読み込み、別の引数の文字列を正規表現で絞り込み、表示する。
procsを読んで見ようと思ってgithubを開いたがよくわからなかった。というか大きすぎない?topの代替にしては。そんなにすることある?と思った。 正直大きすぎるとデバッガを使ってmain()から順序よく読んでいかないことには自分のおつむでは理解できない。
実践Rust入門良き
最近技術評論社のtwitterが流れてきて、PDF,EPUB版の実践Rust入門が第2版となり誤植が修正されたと知り、翌日ほくほくとダウンロードして実際治っているのを確認しました。
wcの作り方、そしてそれを公開させる前にファイルを分割してよりライブラリらしくする工程とかも書いてあって実践的でやる気が出る作りで良いです。
コミュニティの良さ
Rustのslackではバグ報告が盛んでその度に著者が直々に答えていて活発なコミュニティっていいなーと感じました。
言語それ自体のコミュニティには参加したことがなくってPyConJPというカンファレンス大会のslackには参加したことがありました。
でも、実際Pythonの何かが活発に議論されているという感じではなかった。