'Build your own text editor in Rust' を読んだ
• 3 min read
感想
Hecto: Build your own text editor in Rust を手を動かしながら読んだのでそのメモ。
通して読んでみて総論とても良かった。
今まではチュートリアルや言語概要が主だったが、当初の思惑でもあった実践的な開発をこれを通して感じることができた。
具体的にはエディタというアプリケーションを(ほぼ)スクラッチで作っていく過程で、
学習者に OSS を使って自分のコードを置き換えてもらって便利さを味わってもらったり、
場当たり的な条件式や繰り返しのコードをリファクタリングしていくなど、
実際に即した開発を体感できているように感じた。
ひとまず Rust 学習についてはこれでひと段落させて、少し時間をあけて LeetCode などで Rust を使って行こうかと思っている。
読書メモ
以下は読書時メモ
- kilo という OSS のエディタの Rust 版実装
- Chapter 1: Setup
- 特に真新しいことはない
cargo init hectoしただけ
- 特に真新しいことはない
- Chapter2: Reading User Input
- これで標準入力を受け取れる
use std::io::Read; for b in io::stdin().bytes() {} - デフォルトの Rust のバイナリは canonical mode と呼ばれ、標準入力を Enter を押した後に受ける
- また、終了するときは Ctrl + C などを入れる必要がある
- エディタで必要なのは raw mode
- それを実現するための crate がある
termion
- それを実現するための crate がある
- Rust では character の場合は single quote
termion導入into_raw_modeを使って標準出力stdoutを取得している- なぜ
stdoutが 入力であるstdinに影響する?- Terminal は自身のステートを reader ではなく writer によって管理されているから
- writer は screen への描画やカーソルの移動に使われている
into_raw_modeで取得したstdoutはどこにもアサインされていないのに動くのはなぜ?- Rust の所有権 Ownership システムによるもの
_stdoutが存在する限り raw mode が続く_をつけることで未使用変数でもコンパイラによる警告がなくなる
- なぜ
- Observing key presses
- variable shadowing
- Rust では同じ変数名を2度定義できる
println!- macro
- placeholder
{}- print 可能な string representation を持つオブジェクト向け
{:?}- 上記以外
- carriage return
\r- インデントなしで次の行に行ける
println!が\nを入れる前に
- ASCII code
- 0-31 と 127 は control character
- 32-126 がプリント可能
- page up や page down は3~4byteが出力される
- escape sequence と呼ばれる
- 必ず27から始まる
- backspace が 127
- enter は 13、 carriage return
- ctrl + A-Z が 1-26 に割り当てられている
- escape sequence と呼ばれる
- variable shadowing
- Error Handling
- Rust には try catch はない
panic!と return value で Result を使うunwrapは Ok なら中の value、Err ならpanic!の sugar syntax
- これで標準入力を受け取れる
- Chapter 3: Raw input and output
- termion を使って stdin に keys を生やせる
- それを使って
Key::CharKey::Ctrl('q")などで match で分岐する
- それを使って
implのなかで&selfパラメータがない場合はそれは static method になる- Rust で read-only property を作るには
pubを付けずに変数定義して、読み取り用のpub fnを作って参照を返すようにするしかない
saturating_addは結果の値がその型の最大値もしくは最小値を超える場合、その最大最小で返す- カーソルを表示・非表示するのに escape sequence を使う
cursor_positionを editor に入れてるのが面白い- terminal ではないのは、それが screen ではなく document 内の場所だから
- termion を使って stdin に keys を生やせる
- Chapter 4: A text viewer
#[derive(Default)]をつけると、その struct のイニシャライザにdefault()がついてパラメータ初期化を勝手にやってくれる- Rust が default を推測できないパラメータを持つ場合、上記の derive は使えない
env::args()の 0 番目はプログラムの名前、引数の最初は 1- マルチバイト文字などを含め、マウスで選択できる1文字のことをGraphemeという
- grapheme 単位で文字を扱うために
unicode-segmentationをインストール - 時間関連の扱いに、
std::time::Durationやstd::time:Instantがある
- Chapter 5: A text editor
- iterator
takeは 0 から at までskipは at から終わりまで
collectが便利- iterator から collection に変換してくれる
Result型にはis_ok()が使える- 同様に
Optionにはis_none()is_some()がある
- 同様に
&self.file_nameなどへのプロパティの参照は&をつける- これをしないと所有権がうつらない
- bool flag を pub にしないで、 is_flag の pub fn として後悔するのは一般的なのかな?
- read only で pub にできないからかな
clippy::restrictionで lint ぽいことができる- exclude するケースも
[allow(clippy::{rule})]で書く
- exclude するケースも
get_mutで安全に配列にアクセスすることもできるが、予め index check を行い確実にアクセスすることができるなら冗長になるので直接array[index]でアクセスする
- iterator
- Chapter 6: Search
enumerate()で index と value を取得できるのは Swift と同じだなFnの他にもFnMutがあるrfindは見つけた文字列の後ろから数えた index を返すPartialEqは比較できるようにするための trait
- Chapter 7: Syntax Highlighting
- 最初は row 内で直接 digit にのみ色を付けて、そのあとリファクタリングする流れ良い