Rust学習量ディレクトリ
参考:プログラミング言語 Rust, 2nd Edition
- lsコマンド
- redditのr/programmingのポストをfetchとsaveするコマンド
- ディレクトリをJSONに変換するコマンド
- JSONからディレクトリを作成するコマンド
- togglのコマンド実装
- slackのコマンド実装
- Rustスクレーパーを試す
- コンパイラ
- OS
- 軽量フレームワークを作る
- Flaskとか?
- ブログ用のFWとか?
- PJT作成
- cargo new hogehoge
- hogehogePJTの作成
- cargo new hogehoge --lib
- hogehogeライブラリの生成
- cargo new hogehoge
- 実行
- cargo run
- 実行
- cargo c
- コンパイルチェック
- cargo build
- build可能かチェック
- cargo run
- 変数
- 変数は標準で不変(immutable)
- 可変にしたい場合はmutを変数名前につける
- 3章で出てくる
- 参照
- &は参照
- 参照とは・・・?
- 4章で出てくる
- これ、Rustの肝っぽいが、難しそう
- &は参照
- Result型
- 列挙型
- enum
- 6章で出てくる
- クレート???
- ライブラリのこと?
- トレイト???
- 10章に出てくるらしい
- match
- 6章と18章に出てくる
- シャドーイング
- これって便利なのだろうか?
- 混乱しそうなイメージ
- 3章に出てくるとのこと
- 数値型
- 3章
- 変数
- 基本は不変
- mutをつけて可変に
- 定数
- letではなくconst
- 値の型を必ず注釈する
- 命名規則は全て大文字とアンダースコアで単語を区切る
- シャドーイング
- 値に変更は行えるが、再代入ができるわけではない
- letを使わないといけない
- データ型
- スカラー型
- 整数型
- 符号なし:u
- 符号付き:i
- 大きさ
- 8bit:i8 or u8
- arch:isize or usize
- どの整数型を使うべきか
- rustの基準はi32
- 浮動小数点型
- f32とf64がある
- 基準はf64
- 数値演算
- 足し算、引き算、掛け算、割り算、余り
- 論理値型
- true, false
- bool
- 文字型
- char型
- 文字列は””だが、char型は’'
- 整数型
- 複合型
- タプル型
- 複数の型を複合型としてまとめあげることができる
- let tup: (i32, f64, u8) = (500, 6.4, 1)
- 分配:パターンマッチングによる分解
- let (x, y, z) = tup;
- println!(“The value of y is: {}”, y)
- 添字アクセス
- let five_hundred = tup.0;
- 配列型
- 全要素、同じ型
- 固定長
- ヒープよりもスタックにデータのメモリを確保したいとき or 常に固定長の要素があることを確認したいときに有効
- 配列とベクタ型をどちらを使っていいかわからないときはベクタ型を使う
- monthのように変わらない要素ならば配列でおk
- 要素へのアクセス
- let a = [1, 2, 3];
- let first = a[0];
- 配列への無効なアクセス
- パニックを起こす
- タプル型
- スカラー型
- 関数
- 命名規則はスネークケース(some_variable)
- 関数は名前+()で呼び出せる
- どこかで定義すれば呼び出せる
- 関数の引数
- 仮引数は型を宣言しないといけない
- 複数の仮引数を持たせたいときは仮引数の定義をカンマで区切る
- 文と式
- 文は何も返さない
- 式は必ず値を返す
- if式
- 返す値の型は一致していること
- 複数条件が扱いやすくなるmatchは6章
- ループでの繰り返し=> これって全部mapとかで書き換えられしまうのでは?
- loop
- 明示的にやめさせるまで実行する
- breakでやめさせられる
- while
- 条件が真の間、ループが走る
- if, else, breakを使わなくて良いので、分かりやすい
- for
- コレクションを覗き見る
- コレクションの長さに変更に強い
- Rustでの使用頻度が一番高いループ
- loop
- 所有権
- メモリはコンパイラがコンパイル時にチェックする一定の規則とともに所有権システムを通じて管理されている
- 所有権の理解=Rustの理解の礎
- スタックとヒープ
- Rustにおいては値がスタックに載るか、ヒープに載るかは重要
- ???
- スタック:last in first out
- お皿の山のイメージ
- スタックにPush:データの追加
- スタックからPop :データを取り除く
- データへのアクセス方法のおかげでスタックは高速
- スタック上のデータは全て既知の固定サイズにならなければいけない
- ヒープ
- コンパイル時にサイズがわからない or サイズが可変のときはヒープに格納する
- ヒープにデータをおくとき、OSはヒープ上に十分な大きさの空の領域を見つけ、使用中にして、ポインタを返す
- ポインタはその確保した場所のアドレス
- この過程をヒープに領域を確保する:allocateという
- レストランでの座席確保
- 所有権が解決すること
- どの部分のコードがヒープ上のデータを使用しているか把握すること
- お客様がどのテーブルを使っているかを把握すること
- ヒープ上の重複するデータを最小化すること
- レストランのたとえだとムリ?
- メモリ不足にならないようにヒープ上の未使用のデータを掃除すること
- 机の掃除?
- もっと良いたとえがありそう
- どの部分のコードがヒープ上のデータを使用しているか把握すること
- Rustにおいては値がスタックに載るか、ヒープに載るかは重要
- 所有権規則
- Rustの各値は、所有者と呼ばれる変数と対応している
- いかなるときも所有者は一つである
- 所有者がスコープから外れたら、値は破棄される
- 変数とスコープ
- 他の言語とそんな変わらない
- String型
- 8章で深く議論する
- 文字列リテラルは不変
- String型はユーザー入力を受け取るとき(長さが分からないとき)に便利
- ヒープにメモリを確保する
- メモリと確保
- メモリは実行時にOSに要求される
- String::from関数を読んだら、実装が必要なメモリを要求する
- どうやって???
- String::from関数を読んだら、実装が必要なメモリを要求する
- String型を使用し終わったら、OSにこのメモリを変換する方法が必要
- GCはこれを勝手にやる
- ない場合は、自分でメモリを開放する必要がある
- Rustはメモリを所有している変数がスコープを抜けたら、自動でメモリを変換する
- 変数がスコープを抜けるとき、drop関数を読んでメモリを変換している
- ムーブ
- ヒープ上のデータはコピーされない
- スタック上のポインタ、長さ、許容量をコピーする
- shallow copyの最初の変数を無効化する版がRustではムーブとして知られている
- Rustではdeep copyが自動的に行われることはない
- 既知のサイズを持つ型は全てスタック上に保持される
- 型にCopy注釈をつけるには、継承可能トレイトを使う
- メモリは実行時にOSに要求される
- 参照と借用(borrowing)
- &で参照をつけることができる
-
- で参照を外せる(8章、15章)
- 可変な参照
- 変数をmutで可変に
- &mutで可変な参照を作成できる
- 制約:特定のスコープで特定のデータに対しては一つしか可変な参照を持てない
- 利点:データ競合を防ぐことができる
- データ競合はこれら3つの振る舞いが起きるときに発生する
- 2つ以上のポインタが同じデータに同時にアクセスする
- 少なくとも1つのポインタがデータに書き込みを行っている
- データへのアクセスを同期する機構が使用されていない
- スコープが違えば、複数の可変の参照を作成可能
- 可変と不変の参照の組み合わせは不可
- 宙に浮いた参照
- ダングリングポインタ:他人に渡されてしまった可能性のあるメモリを指すポインタで、その箇所へのポインタを保持している間にメモリを開放することで発生する
- Rustはそれを防げるようになっている
- データ参照があった場合は、参照がスコープを抜けるまでデータがスコープを抜けることがないように確認してくれる
- ライフタイムは10章
- スライス
- 良く分かってない・・・が大変なのは分かった
- struct(構造体)とは、意味のあるグループを形成する複数の関連した値をまとめ、名前づけできる独自のデータ型
- オブジェクトのデータ属性のようなもの
- Haskellの型に命名できるやつと同じ?
- 何が嬉しいのか?
- 構造体を利用するには、各フィールドに具体的な値を入れてインスタンスを生成する
- mutで可変インスタンスを生成すれば、フィールドの値を後から変更できる
- フィールドと変数名が同名の場合は、フィールド初期化省略記法が使える
- 構造体更新記法
- user1で定義したものをuser2でも..user1という記法を使うと明示的にセットしなくても残りのフィールドがuser1と一緒になる
- タプル構造体
- フィールドに紐付けられた名前がなく、型だけのものをタプル構造体
- struct Color(i32, i32, i32);
- ユニット様構造体
- 一切フィールドのない構造体
- ある型にトレイトを実装するが、型自体に保持させるデータがないときに使う(トレイトは10章)
- メソッド記法
- 構造体の文脈で定義される
- 関数の代替としてメソッドを使う利点は2つ
- 全メソッドのシグニチャでselfの型を繰り返す必要が無くなる
- 体系化できるようになる
- '->演算子'はないが自動参照、参照外しがある
- CとC++の場合、オブジェクトのポインタに対してメソッドを呼び出し、先にポインタを参照外しする必要があるなら、->を使用する
- Rustのコンパイラはobjectがメソッドのシグニチャと合致するように自動で&, &mut, *を付与する
- 取りうる値を列挙することで型を定義させてくれる
- nullは無く、Option enumがある
- 値がnullである場合を明示的に処理する必要がある
- Rustのmatchは包括的で全ての可能性を網羅しないとコードが有効にならない
- 全ての可能性を列挙したくないときには、'_'が利用できる
- if letを使うと、_ => ()を毎回書かなくて良くなる
- ただし、包括性チェックを失うので注意
- 構造体よりも拡張性があることはわかったが、じゃあ、構造体いらないのでは?とはならないのか?
- cargo でPJT作ってみようがなかったので、コードを書かないで終わってしまった・・・
- モジュールとは関数や型定義を含む名前空間のことで、それらの定義がモジュール外からも見えるようにするか否かを選択することができる
- モジュール規則
- モジュールにサブモジュールがなければ、fooの定義はfoo.rsに書く
- fooというモジュールにサブモジュールがある場合はfoo/mod.rsというファイルに書く
- プライバシー規則
- 要素が公開であれば、どの親モジュールを通してもアクセス可
- 要素が非公開なら、直接の親モジュールとその親の子モジュールのみアクセス可
- useキーワード
- 呼び出したい関数のモジュールをスコープに導入することで関数を短縮化して呼び出せる
- glob *
- ある名前空間要素全てを一度にスコープに導入する
- 名前衝突を引き起こすので多用しないこと
-
vector(ベクタ)
- Vec(T) APIドキュメント
- .get(添字)でベクタの終端を超えて要素にアクセスするとNoneを返す
- パニックを起こさせたいときは[]
- 同じ型しか保持できない
- forループでは、可変参照が参照している値を変更するには、参照外し(*)が必要
- 服薄の型を入れる場合はEnumを使う
-
文字列
- APIドキュメント
- 文字列とはStringと文字列スライスの&strを指す
- 生成
- "test".to_string or String::from("test")
- 更新
- "test".push_str("xxx")
- 添字へのアクセスはできない
- Rustがメモリにどのように文字列を保持しているかを知る必要がある
- 内部表現
- 文字列をスライスする
- UTF8は.chars()で分解して取得する
- バイトの値を入力して、値を取得する
-
ハッシュマップ
- APIドキュメント
- 取り出した結果はSomeに包まれる
- Optionを扱う形になる
- 値の更新
- entryとor_insertを使う
- 文字列リテラルってなんだっけ・・・
- &は借用。ムーブしない
- ジェネリクスとは??(10章)
- 参照外し型強制?????(15章)
- ヒープ
- コンパイル時にサイズがわからない or サイズが可変のときはヒープに格納す