Rust小ネタ集

Proc 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);
}

の例だと、コメントアウトされている方はエラーになるがされていない方はコンパイルが通る。どうも構造体へのメソッド呼び出しが入ると(マングルされた関数本体を探してこなくてはならないからか?)そこでいったん型推論のプロセスが止まってそれ以降のコードは見てくれないみたい。こんな例が見つかった。

Comments

comments powered by Disqus