Rust勉強メモ
型安全性
プログラミングRust 第2版ではこの話がなくなってるぽい
最新のRustではextern crateは必要ない
pub struct Request<'a, 'b: 'a> {の<'a, 'b: 'a>の部分の意味とは
Request https://docs.rs/iron/0.6.0/iron/request/struct.Request.html
'aや'bは生存期間パラメータ?
pub struct Request<'a, 'b> where 'b:'a
whereはトレイトバウンドを書く記法
'bは'aより長く生きる(outlive)
non-lexical lifetimeにより「内包」ではなく「outlive」という
ironのRequest, ResponseはCGIでも使えるかもしれない
単純並列(embarrassingly parallel)
let output = File::create(filename)?;
code:Rust
let output = match File::create(filename) {
Ok(f) => { f }
Err(e) => { return Err(e); }
};
?はOption, Resultで使える
let args: Vec<String> = std::env::args().collect();
args()はArgsを返す
collect()はイテレータをコレクションに変換するメソッド
https://zenn.dev/garasubo/articles/redox-syscall
code:Rust
let scratch = &stack.scratch;
syscall::syscall(scratch.rax, scratch.rdi, scratch.rsi, scratch.rdx, scratch.r10, scratch.r8, rbp, stack)
&stack.scratchのようにポインタを取っているのに、使うときはscratch.raxとか「.」でいいの?
もしlet scratch = stack.scratchと書いたら?
stack.scratchがscratchに移動される
cargo 2018 editionが結構大きな変更が入った
table:image 0.13.0 → 0.24.2の違い
項目 0.13.0 0.24.2
エンコーダーの型 image::png::PNGEncoder image::codecs::png::PngEncoder
エンコード関数 encode write_image
エンコード関数の戻り値 std::io::Result<()> image::error::ImageResult<()>
0.13.0のPNGEncoder
0.24.2のPngEncoder
table:エラー型の深掘り
展開前の型 展開後の型
std::io::Result<()> std::result::Result<(), std::io::Error>
image::error::ImageResult<()> core::result::Result<(), image::error::ImageError>
std::result::Result と core::result::Result の違いとは?
std::result::Result のドキュメントURLに "nightly" が含まれるのがミソ?
https://doc.rust-lang.org/nightly/std/result/enum.Result.html
code:Text
errorE0308: mismatched types
--> src/main.rs:133:29
|
133 | let bounds = parse_pair(args2, 'x').expect("failed to parse PIXELS");
| ^^^^^^^
| |
| expected &str, found struct String
| help: consider borrowing here: &args[2]
&strとStringの違い
Stringを借用すると&strになる?
args: Vec<String>
&strとString
String: ヒープ上のバイト列を指すポインタ、容量、長さを持つデータ構造(3ワード)
&str: ヒープや読み出し専用メモリなど、任意の場所のバイト列を指すポインタと長さを持つデータ構造(2ワード)
Stringの変数に対し&を適用すると&strを得られる
code:Rust
let noodles = "noodles".to_string();
let oodles = &noodles1..;
let poodles = "ಠ_ಠ";
https://gyazo.com/03983fc41de82dddd304b38b902017e6
「プログラミングRust 第2版」p.65
strと&str
https://doc.rust-lang.org/1.60.0/std/primitive.str.html
strは文字列スライス
文字列リテラルの型は &'static str
&strはバイト列へのポインタと長さから構成される
code:Rust
let story = "Once upon a time...";
let ptr = story.as_ptr();
let len = story.len();
releaseビルドの威力
$ time target/release/mandelbrot mandel.png 4000x3000 -1.20,0.35 -1,0.20
real 0m1.819s
user 0m1.809s
sys 0m0.010s
$ time target/debug/mandelbrot mandel.png 4000x3000 -1.20,0.35 -1,0.20
real 0m30.495s
user 0m30.495s
sys 0m0.000s
borrowed typeは常に大きさがコンパイラに分かる
code:Text
errorE0277: the size for values of type str cannot be known at compilation time
--> src/main.rs:9:14
|
9 | fn print_str(s: str) {
| ^ doesn't have a size known at compile-time
|
= help: the trait Sized is not implemented for str
help: function arguments must have a statically known size, borrowed types always have a known size
|
9 | fn print_str(s: &str) {
| +
この点で、borrowed type(&foo)はポインタを取る操作に似ている
ポインタもサイズが自明である
(-4_i32).abs()とi32::abs(-4)
absは無引数のメソッドでもあるし、1引数のグローバル関数でもある?
それとも、一般にメソッドはselfを第1引数として呼び出すことができる?
assert_eq!(5., 5f32.sqrt() * f32::sqrt(5.0));
https://doc.rust-lang.org/reference/expressions/call-expr.html#disambiguating-function-calls
符号付き整数の最小値の特別扱い
128_i8はエラー
-128_i8はコンパイルが通る
一般に負数は正数に「-」演算子を適用することで得る
2の補数表現の世界では、符号付き整数の最小値はその処理では得られない
→コンパイラがそのケースを特別に処理しているらしい
ラッピング演算版のビットシフト
assert_eq!(5_i16.wrapping_shl(17), 10);
5<<17で0になるかと思いきや、10になる
ラッピングにより(17%16)=1ビットだけ左シフトされる
assert_eq!(0xef00_u16, 0xbeef_u16.wrapping_shl(8));
assert_eq!(0xeef0_u16, 0xbeef_u16.wrapping_shl(20));
これらの挙動はx86 CPUのシフト命令と同じらしい
x86では、レジスタのビット幅でマスクした値をシフト量として用いる
浮動小数点数のmin,max
C++ではstd::numeric_limits<double>::min()は「浮動小数点型については正の正規化数のうち最小のものを返す。」
https://cpprefjp.github.io/reference/limits/numeric_limits/min.html
Rustではassert_eq!(-f32::MIN, f32::MAX);
C++のmin()に相当する定数は持ってないのかな?
f32::MIN_POSITIVE
?as演算子と変換コスト
「Rustでは、as演算子は、安価で失敗することのない変換のみに限定している。」
「プログラミングRust 第2版」p.53
例外はないのだろうか?
プリミティブ型にのみ使えるらしい
asは型注釈として使うこともあるぽい?
assert_eq!の等価性判定
何を持ってequalと言っている?
code:Rust
let text = "I see the eigenvalue in thine eye";
let (head, tail) = text.split_at(21);
assert_eq!(head, "I see the eigenvalue ");
assert_eq!(tail, "in thine eye");
&strはバイト列へのポインタとバイト列の長さの組
headと"I see the eigenvalue "は実体としては異なるバイト列を指すはず
なのにequalと判定される
UTF-16
WTF-16, WTF-8 本来のUnicodeではないダメなやつ
文字列の等価性判定
文字列は、演算子==と!=をサポートする。2つの文字列は同じ文字を同じ順番で持っていれば、同じだと判断される(メモリ上の同じ場所を指していなくてもよい)。
「プログラミングRust 第2版」p.67
&の発音
型&String(「ref String(レフストリング)」と発音する)
「プログラミングRust 第2版」p.56
参照と借用
型&String(「ref String(レフストリング)」と発音する)は、String値への参照で、&i32はi32値への参照である。
式&xはxへの参照を作るが、Rustの用語では、これを「xへの参照を借用する」と言う。
「プログラミングRust 第2版」p.56
「参照」を「借用」するという概念
共有参照と可変参照
&Tは複数作れる
&mut Tは、これが存在する間はその他の(共有、可変)参照を作れない
rawポインタ
*mut Tは&mut Tみたいな感じ?
*const Tは&Tみたいな感じ?
なぜ*Tとしなかったのか
配列とスライス
[T;N]は配列
&[T]はスライス参照
&strはスライス参照
Rustは、メソッド探索時に、配列への参照を暗黙にスライスに変換する
「プログラミングRust 第2版」p.58
ということは、逆に言えば「配列への参照」≠「スライス」ということか。似てるだけで別物。
配列、Vec、スライス
配列やVecからスライスを借用できる
code:Rust
let v: Vec<f64> = vec!0.0, 0.707, 1.0, 0.707;
let a: f64; 4 = 0.0, -0.707, -1.0, -0.707;
let sv: &f64 = &v;
let sa: &f64 = &a;
Rustでも、Cと同じように構造体の最後にだけスライスを突っ込めるらしい
その構造体自体もUnsizedになる
ベクタのマクロ
vec!マクロは、新しい空のベクタをVec::newで作ってから要素を追加するのと等価だ。
「プログラミングRust 第2版」p.59
vec!の場合は最初から要素数が分かるから、動的にpushで追加するより効率的に実装できそうだけども
やってるらしい
vec!マクロは、最終的なベクタが持つべき要素数がわかっているので、実はこのようなことを行っている
「プログラミングRust 第2版」p.60
関数型言語の定義
code:sh
$ cargo run Lisp Scheme C C++ Fortran
Compiling proglangs v0.1.0 (/home/jimb/rust/proglangs)
Finished dev unoptimized + debuginfo target(s) in 0.36s
Running target/debug/proglangs Lisp Scheme C C++ Fortran
Lisp: functional
Scheme: functional
C: imperative
C++: imperative
Fortran: imperative
ついに、関数型言語(functional language)という言葉の満足できる定義が得られた。
「プログラミングRust 第2版」p.61
Redoxを読む会#3(2022/5/23)ここまでやった
ファットポインタ
スライスの先頭を指すポインタ
スライスの要素数
2ワードの値
?スライス?スライスへの参照?
code:Rust
let v: Vec<f64> = vec!0.0, 0.707, 1.0, 0.707;
let a: f64; 4 = 0.0, -0.707, -1.0, -0.707;
let sv: &f64 = &v;
let sa: &f64 = &a;
sv、saは「スライス」なの?「スライスへの参照」なの?
配列やベクタのある領域を指すスライスは、長さを指定せず[T]のように書く。
「プログラミングRust 第2版」p.61
ということは&[f64]は「スライスへの参照」と言えそう
スライスは、ほとんど常に参照を経由して使うので、&[T]や&strを「スライス」と呼ぶことがある。
「プログラミングRust 第2版」p.63
?&[u8]と&str
&strが特別に用意されているのは、UTF-8として成り立つバイト列を指すことが保証される型を用意したかったから?
&[u8]と&strは、メモリ上は同じレイアウトになると思っていい?
?to_stringとto_ownedのニュアンスの違いとは
.to_owned()メソッドも同じことをする。
「プログラミングRust 第2版」p.66
to_owned()はborrowingからownedに変換する
strに関して、to_stringと同じ挙動となる
Rust勉強メモ/所有権と移動
Rust勉強メモ/参照 Redoxを読む会#5(2022/7/18)ここをやった
Rust勉強メモ/式
Rust勉強メモ/エラー処理
Rust勉強メモ/クレートとモジュール
Rust勉強メモ/列挙型とパターン
Rust勉強メモ/トレイトとジェネリクス
Rust勉強メモ/イテレータ
Rust勉強メモ/コレクション
Rust勉強メモ/文字列とテキスト
プログラミングRust 第2版 誤字脱字
Redoxコードリーディングメモ Redoxを読む会#5(2022/7/18)ここをやった