Rust小ネタ集
Wed, Jun 10, 2020Proc macroのprintfデバッグ
println!
デバッグが使えないのでなんか情報を出したくなったときに困るが、代わりにpanic!
マクロが使える。panic!
のメッセージはそのまま表示される。
bytes crate
Rc
なんだけど、でかい配列の一部分を参照しているオブジェクトに関しても参照カウンタを増やしてくれる便利な子
なぜAny
は'static
を要求するか
'static
がなかったらと思うとなかなかカオス。lifetimeはより短い方には切り詰められるので、lifetimeの依存関係の情報を持たせなければならない。実行時に決定できるかが問題。最もナイーブなケースではスタックフレームを全部追いかけていけば原理的には不可能ではないような気もするが、 常に 可能であると証明できるか?かなり非自明。そもそもスタックフレームとかに依存していいんでしたっけ?(stackful coroutineをやってはいけないと言われている?)
generic-array
配列の長さを無理やりジェネリクス化する。言い換えればジェネリクスで無理やり「ちょっとした依存型」を実現する。ちょっとした依存型に関してはそもそもtypenum
というのがある。
BufReadとRead::read
そもそもの勘違いとしてread(2)は問答無用でcount
(第三引数) bytes待つんだと思っていたんだけど、そんなことはない。man曰く、
It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of- file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
だそうで。例えばmkfifo
したfifoにread(2)をすると、もし読まれていないデータがあればそれだけ読んで返し、何もないときだけblockする。
で、read(2)に対応するのはRead::read(&mut self, buf: &mut [u8])
なんだけど、これもbuf.len()
bytes読むまで待つとは限らない。例えばfifoから読むときはreadyなデータだけ読んで返ってくる。さらに、BufReader
のようにバファリングするstructのときは、internalなバッファの残りより大きなデータを読もうとしてもinternalなバッファの分しか読まずに返ってきてしまう。
というわけで ―これは一般論なんだけど― readしてほしい分だけのデータが確実に返ってくると期待するのはまずい。こういう用途の場合、Rustの場合は代わりにRead::read_exact
というメソッドがあってこれを使える。もちろんBufReader
にかませておけばバファリングしてくれる。同じことをCでやりたければ
#include <unistd.h>
int read_exact(int fd, void* buf, int count) {
int r;
while (r = read(fd, buf, count)) {
if (r < 0) return r;
buf += r;
count -= r;
}
return 0;
}
とかすればいいだろう。(まあ、あんまり使う機会はなさそうだけど。)
Rustの型推論の順番
RustはHM型推論を実装していて、HM型推論は式の順番にかかわらず型を推論してくれるのでC++のauto
とかと違って使いやすい、みたいなことをたまに言うけど、Rustの型推論でも実はたまに順番依存になってしまい推論がうまくいかなくなることがある。例えば
use std::collections::HashMap;
fn main() {
let mut hoge = HashMap::new();
/* if hoge.contains_key("foo") {
hoge.get_mut("foo").unwrap().push("bar".to_owned());
} else {
hoge.insert("foo".to_owned(), vec!["bar".to_owned()]);
} */
if !hoge.contains_key("foo") {
hoge.insert("foo".to_owned(), vec!["bar".to_owned()]);
} else {
hoge.get_mut("foo").unwrap().push("bar".to_owned());
}
dbg!(hoge);
}
の例だと、コメントアウトされている方はエラーになるがされていない方はコンパイルが通る。どうも構造体へのメソッド呼び出しが入ると(マングルされた関数本体を探してこなくてはならないからか?)そこでいったん型推論のプロセスが止まってそれ以降のコードは見てくれないみたい。こんな例が見つかった。