Top

RustでWebアプリ開発日記

今後記事として書けそうなネタ

2020/08/14

今ならremove_first関数をもっと綺麗に書ける。成長しているみたいで嬉しい。

インデントは2にしている。C++を書いているときの感覚と同じにしたいから。

関数の戻り値としてStringや構造体が普通に使える理由について考える。

これらの実体はヒープに格納されているため、関数から抜けても確保し続けることができる。呼び出し元にはその領域を指すポインタを返すと考えれば良さそう。そしてそれは、所有権を呼び出し元に移すことを意味する。

指すヒープ領域が関数内で作成した構造体ではなく引数として渡された構造体であるとき、ライフタイムを考える必要がある。

パターンの中で&&mutを使いたくなったときにrefref mutを使う。

パターンに一致したときに所有権の移動が起こるため。

2020/08/13

Deferトレイトの項を読み終えた。
Deferトレイトを実装している型の変数に対しては*をつけることができ、これをつけることで参照を外すことができる。イメージ的にはポインタから値を得る感じ。
Box型はDeferトレイトの実装であるため、*によって参照を外すことができる。そして、もしBox<String>であるなら、StringもまたDeferトレイトの実装であるため*が使える。よって、let x: Box<String>;**xといった記述が可能。
…だと思うけど、今実験すると**x&str型ではなくstr型になった。Stringの参照を外すとstrになるっぽい?


所有権を剥奪する仕組みの有難みが並行プログラミングを学んでいるとわかる。

std::mpsc::channel()により作成したチャンネルのtx.send()を使って変数valのデータを送信すると、その送信後にvalが使えなくなる。これは、受信側にvalの所有権が移ったから。意味的には、「送信したデータをまだ扱えるのなら、送信側が変更できたりしてしまっておかしくなるよね」となる。

Rustのルールと並行プログラミングの考え方がマッチしていて面白い。

rxがイテレータとして扱えるのが好き。

2020/08/12

エラー処理の項を読み終えた。
Resultを使うかpanic!を使うかの判断基準が明確に定められていて面白かった。
あと、データの正当性チェックを外部に追い出すためにenumimplを使うというのはなるほどと思った。

ライフタイムについてある程度理解した。
ライフタイム注釈を行ったからといって、ライフタイムを長くしたり短くしたりすることはできない。
そして、同じライフタイム注釈だからといってライフタイムの長さを同じにしないといけないというわけではない。このあたりはジェネリクスと異なる。

チュートリアルを再開してからまだ一度もトレイトを使っていないので、これからトレイトを使ってみる。


newResult<T, U>を返してもいいとは思わなかった。
それはしてはいけないことだと思っていた。


所有権を奪うような実装は避けるべきだと思っていたけど、実はそうではないみたい。リファクタリングにより、Config::new()の引数を借用ではなく所有権を奪う形に修正している。こうすることで値のクローンが発生せずに効率的とも書かれている。


「再帰的な型を定義するためにBoxを使用する」というのは、TypeScriptの型システムを理解するときの手助けになりそうな概念。コンパイラが列挙型のサイズを決定するとき、列挙されているデータのうちで最も大きいサイズのものにする。ここで、たとえばenum List { Cons(i32, List), Nil }のように定義してしまうと、Cons(i32, List)のサイズを決めるためにListの定義を見に行くけど、そこでもまたCons(i32, List)が存在して…というように再帰的になっており、サイズを決めることができなくなる。そこでCons(i32, Box<List>)とすることで、Cons(i32, Box<List>)のサイズはi32と、ヒープに存在するList型への参照の大きさを合わせたサイズだとわかる。

2020/08/11

Rustのチュートリアルを進めている。
先ほど「8.3. ハッシュマップ」を終えた。そして演習問題を解いた。
解くことはできたけど、もっと簡潔な方法が存在する気がする。

知らないプログラミング言語を使うといつもこの感覚を味わう。
C++を学びたての頃も、文字列の各文字にアクセスする方法が添え字アクセス以外にも存在し、そちらのほうが良いと思っていた。
しかし実際は、確かに文字列をイテレータのように扱う方法は存在するが、それよりも添え字アクセスのほうが自然であり高速である。

このように、最初に学んだ方法が悪い方法ではないこともある。
特に今回はRustの公式のチュートリアルを進めているので、学ぶ方法が悪い方法でないことは確かだ。もっと効率の良い方法は存在するかもしれないが、基礎さえ見についていればおそらくすぐに理解できる。


次のような問題を考える。

文字列を受け取ると、先頭文字を取り除いた新たな文字列を返す関数を作成してください。もし元の文字列が空文字である場合はNoneを返してください。

この問題を次のように実装した。

次のような不安がある。


面白い文章を見つけた。
公式の文章に、ある関数の戻り値の型を調べる方法として、APIのドキュメントを確認するほかにもコンパイラに確認することもできると書かれていた。わざとコンパイルエラーを発生させて型を確認するという方法が公式で認められているとは思わなかった。

Rustのチュートリアルを進めていると、仕組みに感動したり常識が覆されたりする。


Result<T, E>Option<T>がたまにごっちゃになる。