タグ

ブックマーク / qnighy.hatenablog.com (48)

  • Rustのモジュールを詳細に理解する(1) モジュール入門 (この回は簡単です!) - 簡潔なQ

    概要: Rust2018以降、Rustのモジュールシステムは入門しやすく、かつマスターしにくくなりました。そこで記事では、その両方を達成することを目指しました。 モジュール入門 名前解決の役割と用語 モジュールグラフの構造 インポート解決 可視性 パス解決 名前解決とマクロ 記事は2017年に書いた記事 (https://qnighy.hatenablog.com/entry/2017/03/27/070000, https://qnighy.hatenablog.com/entry/2017/04/24/070000 ) と同じテーマで、Rust2018を考慮して改めてまとめ直したものです。 モジュールとは モジュールはRustのプログラムを分割する単位のひとつです。ワークスペース・クレート・モジュールという単位になっていると考えてください。 ワークスペースは関連するライブラリ(クレ

    Rustのモジュールを詳細に理解する(1) モジュール入門 (この回は簡単です!) - 簡潔なQ
    xef
    xef 2019/05/07
  • Rustの日付時刻処理(std::time, time, chrono) - 簡潔なQ

    標準ライブラリ 標準ライブラリには時刻を扱うための基礎となる型のみが定義されている。暦やタイムゾーンなどを扱うときは後述の chrono を使うのがよい。 std::time::Duration ... 時間。 std::time::Instant ... 体内時計の時刻。 std::time::SystemTime ... 時計の時刻。 Duration 時間はOSとは無関係なのでlibcoreに定義されている。 src/libcore/time.rs pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC } したがってこれは0秒以上264秒未満の範囲内の時間をナノ秒単位で正確に表現できる。 InstantとSystemTime 標準ライブラリには時刻を表す型が Instant

    Rustの日付時刻処理(std::time, time, chrono) - 簡潔なQ
    xef
    xef 2019/04/27
  • PhantomDataまとめ - 簡潔なQ

    概要: PhantomData<T> には3つの異なる役割があり、多くの場合は PhantomData<fn() -> T> の形で使うのが無難である。 はじめに PhantomData<T>は特殊な型で、中身を持たないにもかかわらず、型システム上は中身を持つかのように振る舞います。幽霊型 (phantom type) と関係はありますが、幽霊型そのものではないので注意が必要です。 PhantomData の基的な使い方 幽霊型を使う場合や、何らかの理由で構造体の外部にある型を指定する必要がある場合を考えます。例えば、幽霊型で単位を区別する // U は Meter や Miles のような型が入るとする struct UnitFloat<U: Unit> { inner: f64, } や、外部にあるデータを参照する struct ExtVec<T> { // 中身はなし } のような

    PhantomDataまとめ - 簡潔なQ
    xef
    xef 2018/12/20
  • RustのREPL "evcxr" を使ってみた - 簡潔なQ

    概要 evcxrはRustのパーサーとコンパイラを外部から呼び出すことでREPLを実現している。セミブラックボックス的なアプローチにも関わらずなかなかの完成度で、今後が期待できる。 evcxr evcxrは最近公開されたRustのREPL (GitHub, redditのpos)である。また、Jupyterのカーネルもあるため、Jupyter Notebook上でRustを書くこともできる。 Evaluation Context for Rust とのことで、 ev + cx + r と思えば覚えられる。 インストール方法 コマンドラインは以下で入る。 cargo install evcxr_repl Jupyter版については公式サイトを参照するとよい。 基的な動作を試してみる。 $ evcxr Welcome to evcxr. For help, type :help >> :he

    RustのREPL "evcxr" を使ってみた - 簡潔なQ
  • ISUCON8にRustで参加するためにしたこと - 簡潔なQ

    背景 ISUCONとは、与えられたWebサービスをいい感じにスピードアップするコンテストである。 いい感じに最適化すさえすれば言語は問われない。ということは、最初に提供される参照実装の書かれた言語を使うのが得策である。 複数の言語で参照実装が提供されることはあるが、Rust版が提供される可能性は高くない。 まず、ISUCONではないコンテストをする覚悟を持つ http://isucon.net/archives/52012898.html 競技の成り立ちにも由来しますが、ISUCONは参加して学ぶことではなく「勝つこと」が前提となっているイベントです。 とある。↑に書いたように参照実装でない言語を好んで使うということは割とこれに反しているし、ISUCONで来得られる経験の一部を「IShokU CONtest」の経験に変換することになる。(オペレーション担当が必死にログを見ている傍らでひた

    ISUCON8にRustで参加するためにしたこと - 簡潔なQ
  • Rustのstaticいろいろ - 簡潔なQ

    概要: Rustのstaticの亜種をいろいろ挙げる。 ここでは以下のように分類します。 変数 ローカル束縛 (引数、 let, match, for, if let, while let) 静的変数/定数 コンパイル時定数 (const) アイテム位置の定数 トレイトの定数 実装の定数 静的変数 (static) 非スコープ借用される静的変数 組み込み static lazy_static! futures-0.2 task_local! スコープ借用される静的変数 thread_local! scoped_thread_local! futures-0.1 task_local! 目次 const と static の違い スコープ借用と非スコープ借用 組み込み static lazy_static! thread_local! scoped_thread_local! futures

    Rustのstaticいろいろ - 簡潔なQ
    xef
    xef 2018/06/19
  • SATySFi用Vimプラグインを作った - 簡潔なQ

    タイトルの通りふと思い立ってSATySFi用のVimプラグインを作ったので紹介します。 https://github.com/qnighy/satysfi.vim SATySFi とは SATySFiはgfn氏が未踏プロジェクトとして開発している組版システムです。LaTeXのような美しい組版を、一から設計しなおしたまともな言語で行うことができるのが特徴です。 SATySFiはプログラムパートにOCaml風の関数型言語、組版パートにLaTeX風のマークアップ言語を使い、準クオートのような構文で両者を切り替えながら文書を記述します。組版結果はPDFとして直接出力されます。 satysfi.vimの機能 satysfi.vim は現在、シンタックスハイライトと自動インデントを提供します。 SATySFiの持つモードを正しく識別してハイライトします。例えば let はプログラムモードではハイライト

    SATySFi用Vimプラグインを作った - 簡潔なQ
  • Rustのパニック機構 - 簡潔なQ

    概要: Rustのパニック機構は異常終了の処理を安全に行うためにある。この動作を詳しくみていく。 パニックとは何か Rustには2つの異なる例外処理機構があります。 発生源 対処方法 例 パニック プログラミングエラー 原則として捕捉しない assert!() 境界外参照 Result 例外的な入力 必要に応じて捕捉 I/Oエラー (File::read) パースエラー (str::parse) パニックとResultの関係についてはTRPL第2版第9章、未定義動作とパニックの関係についてはRustonomiconのUnwindingの章などが参考になります。 パニックを想定した安全性 Rustではたとえパニック状態でも未定義動作だけは絶対に避ける必要があります。そのため以下の関数は不健全 (unsound)です。 use std::ptr; // この関数はRustではunsound (

    Rustのパニック機構 - 簡潔なQ
    xef
    xef 2018/02/19
  • Rustの関数ポインタの落とし穴 - 簡潔なQ

    概要: Rustの関数ポインタの落とし穴について その1: 関数ポインタはクロージャとは異なる これはC/C++に慣れている人には当たり前ですが、関数ポインタ型 (fn()) とクロージャ型 (Fn()) には重大な違いがあります。それは、関数ポインタは環境をキャプチャーしないということです。大雑把にいうと、 関数ポインタは、ある機械語コードのアドレス クロージャは、関数ポインタと、キャプチャーした環境の対 なので、関数ポインタは、ひとつのプログラムにつき原則として有限個しかないのに対し、クロージャは、キャプチャーする環境によって無限にたくさんのクロージャを作ることができます。例えば、 fn main() { let closures = [3, 7, 1, 5, 8, 9, 2].iter().map(|&i| { move |j| i + j }).collect::<Vec<_>>(

    Rustの関数ポインタの落とし穴 - 簡潔なQ
    xef
    xef 2018/02/11
  • 安定化間近!Rustのimpl Traitを今こそ理解する - 簡潔なQ

    概要: impl Trait が安定化間近である。これはトレイトオブジェクトと似た用途を持つが、静的ディスパッチされSizedのまま使えるため効率的である。 impl Trait が安定化間近 Rustでは新規の機能はまずnightlyバージョンに「不安定機能 (unstable feature)」として取り入れられます。そこでの実験を経て、プログラミング言語Rustに半恒久的に導入してもよいと合意されたものだけが「安定化 (stabilize)」され、betaやstableバージョンのコンパイラでも使用できるようになります。 さて、現在 「impl Trait」と呼ばれる機能の安定化のめどがたったというアナウンスがありました。この機能は2016年夏ごろに実装され、長い間待ち望まれてきた目玉機能のひとつでしたが、ここにきてようやっと、という感じです。そこで、 impl Trait について

    安定化間近!Rustのimpl Traitを今こそ理解する - 簡潔なQ
    xef
    xef 2018/01/29
  • Drop Checkerの規則をちゃんと理解する - 簡潔なQ

    概要: Drop CheckerはRustのボローチェッカに付属する追加の検査器で、コンパイラが自動で挿入するdrop処理の安全性を保証するためのものである。これの詳細な規則とその正当性を理解したかったので自分なりに整理した。 dropckの概要についてはRustonomiconの説明とか以前の記事とかを参照。 注意: 記事の内容はコンパイラの実装との対応をとっていないので実際の実装とは異なる可能性がある。 規格 RFC 0769: Sound Generic Drop RFC 1238: Nonparametric Dropck RFC 1327: Dropck Param Eyepatch 用語 Drop::drop(): ユーザー定義のデストラクタ自体 mem::drop_in_place(): 値をデストラクトするために Drop::drop() を再帰的に呼び出す一連の手続き

    Drop Checkerの規則をちゃんと理解する - 簡潔なQ
    xef
    xef 2018/01/02
  • RustのRFC一覧 (~0500) - 簡潔なQ

    概要: RustのRFCの一覧を作ろうとしたが、あまりに多いのでとりあえず0500までで公開することにした。なお、単に全てのRFCを列挙したいならばここを見ればよい。 このRFCはRustのコミュニティーが管理しているものであり、 “RFC” の元祖であるIETF RFCとは関係ない。いずれもrequest-for-commentの略である。 メタ RFC 0002 Rust RFCの提出プロセスの説明 スタイル/慣習 RFC 0199 似たような動作で、所有権/借用の種別だけが異なるようなメソッドの命名規則を定める RFC 0236 panic!/Result の使い分けの慣習を定義する、関連するメソッドの命名規則を定める RFC 0240 unsafe の慣習の整理: unsafe 関数をメソッドにする条件の定義、論理的な不変条件を壊すが未定義動作を引き起こさない関数は unsafe

    RustのRFC一覧 (~0500) - 簡潔なQ
    xef
    xef 2017/07/11
  • RustのRFC一覧 (~0200) - 簡潔なQ

    この記事は古いのでこちらをご覧ください 概要: RustのRFCの一覧を作ろうとしたが、あまりに多いのでとりあえず0200までで公開することにした。なお、単に全てのRFCを列挙したいならばここを見ればよい。 このRFCはRustのコミュニティーが管理しているものであり、 “RFC” の元祖であるIETF RFCとは関係ない。いずれもrequest-for-commentの略である。 メタ RFC 0002 Rust RFCの提出プロセスの説明 スタイル RFC 0199 似たような動作で、所有権/借用の種別だけが異なるようなメソッドの命名規則を定める 構文 RFC 0016 属性を let 文、ブロック、式にも使えるようにする (#![feature(stmt_expr_attributes)]) RFC 0049 マッチ腕に属性を使えるようにする RFC 0059 ~T 型と ~x 式を

    RustのRFC一覧 (~0200) - 簡潔なQ
    xef
    xef 2017/07/09
  • Rustのトレイト選択 - 簡潔なQ

    概要: トレイト選択とは、トレイト制約の解決方法を検索するコンパイラの処理であり、型推論にもコード生成にも使われる重要な部品である。記事ではトレイト選択の動作の詳細について解説する。 トレイト選択とは トレイト選択 (selection) とは、トレイト制約 (obligation) の解決方法を検索する処理である。トレイト制約は、トレイト境界と同じく、 SomeType: SomeTrait<SomeArguments> という形式をとる。例えば、 let z = x + y; というコードを書いたとき、 z の型は <X as Add<Y>>::Output であるが、これをより具体的に決定するには、 X: Add<Y> の解決方法を決定する必要がある。 トレイト選択の処理はtraits/select.rsにまとまっているのでここを読むとだいたいわかる。 トレイト選択が呼ばれるタイミ

    Rustのトレイト選択 - 簡潔なQ
    xef
    xef 2017/07/08
  • Rustにおける演算子の型推論の特殊ルール - 簡潔なQ

    概要: 原則として x + y は ::std::ops::Add(x, y) の構文糖衣であるが、型推論で特別扱いされる。 演算子の脱糖 演算子の脱糖は型推論の後、HIRからMIRへの変換のタイミングで行われる。原則として x + y は ::std::ops::Add(x, y) の構文糖衣である。これは *x/x[i] 以外の他の演算子についても同様である。しかし型推論では以下のような特殊扱いがある。 fn main() { use std::ops::Add; let x : i8 = 1 + 1; // OK let x : i8 = Add::add(1, 1); // Error } 下側のコードがエラーになる理由 Rustの演算子はオーバーロード可能であり、型の制約が少ない。具体的には「左辺と右辺の型から、計算結果の型が一意に決まる」ということだけが要請される。そのため型

    Rustにおける演算子の型推論の特殊ルール - 簡潔なQ
    xef
    xef 2017/06/26
  • Rust パターンマッチの網羅性 - 簡潔なQ

    Rustのパターンマッチは網羅性が検査され、網羅的でない場合はコンパイルエラーになる。網羅性は以下のように検証される。 型の分類 パターンマッチの網羅性をするときには、全ての型がADTのように扱われる。つまり、有限個の引数をとるコンストラクタが有限個あり、そのいずれかにより生成されていると仮定して、網羅性が判定される。 constructor_arity あたりを読むとわかるが、例えば、 通常のADTは、そのままその意味でADTとみなされる。 ただし、空なADTであっても、空であることが今いるモジュールからわからない場合は、余分なコンストラクタを持っているとみなされる。 bool は true と false の2つのコンストラクタからなるとみなされる。 u8 や i32 などはオープンな型とみなされ、全ての定数を網羅しても網羅的とはみなされない。これを修正する提案がある。 参照は単一のコ

    Rust パターンマッチの網羅性 - 簡潔なQ
    xef
    xef 2017/06/15
  • RustでOptionやResultの配列ができてしまったときの一般的なテク4つ - 簡潔なQ

    Vec<Result<_>> ではなく Result<Vec<_>> を得る collect() 関数を使うと、 Vec<Result<_>> を得ることもできるし、 Result<Vec<_>> を得ることもできる。変換先の型を明示することで区別する。 fn main() { // 全てSomeならSome(配列)を返し、どれかがNoneなら全体もNoneになる assert_eq!([Some(1), Some(2)].iter().cloned().collect::<Option<Vec<_>>>(), Some(vec![1, 2])); assert_eq!([None, Some(2)].iter().cloned().collect::<Option<Vec<_>>>(), None); } これができるのは以下の理由による。 FromIterator は多対多である。つま

    RustでOptionやResultの配列ができてしまったときの一般的なテク4つ - 簡潔なQ
    xef
    xef 2017/06/15
  • Rustの構造体/列挙型フィールドの並べ替え - 簡潔なQ

    現在の安定版では無効化されているが、Rustのbeta/nightlyには構造体/列挙型フィールドの自動並べ替えが実装されている。この動作を説明する。 例 以下のようなプログラムを書くと、現在の安定版では6が表示され、beta/nightlyでは4が表示される。 use std::mem::size_of; struct A(u8, u16, u8); fn main() { println!("{}", size_of::<A>()); // 6 or 4 } これはアラインメントと関係がある。通常 u8 は1バイト、 u16 は2バイトの境界に揃えられている必要がある。そのためこの構造体/列挙型のフィールドを宣言順に並べると、 u8, 1バイトパディング、 u16, u8, 1バイトパディング となる。 (配列として並べることもあるため、最後にもパディングが必要である。) 一方、これを

    Rustの構造体/列挙型フィールドの並べ替え - 簡潔なQ
    xef
    xef 2017/06/10
  • Rustの配置構文とbox構文 - 簡潔なQ

    概要: Rustの不安定機能である配置構文とbox構文の仕組みを説明する。 配置構文の動機 Rustの値渡しはデフォルトでムーブであり、コピーコンストラクターのような重い処理が勝手に実行されることはないから、多くの場面では値渡しのコストはそれほど高くない。それでも、大きな構造体を受け渡すと memmove のコストが高くつく場合がある。 とりわけ、データ構造に値を追加する場面では、無駄なムーブが発生している可能性が高い。これを最適化するために、ライブラリのインターフェースに工夫を加えるのが、Rustの配置構文である。C++emplace_back と似ていると考えてよいだろう。 配置構文の使い方 配置構文の具体的な構文は、以下の2種類が提案されており、今のところは確定していない。 in PLACE { EXPR } 構文 PLACE <- EXPR 構文 PLACE の部分は、配置構文

    Rustの配置構文とbox構文 - 簡潔なQ
    xef
    xef 2017/06/08
  • Rustの型推論の概略 - 簡潔なQ

    概要: Rustの型推論の大枠を説明する。 なお、筆者もRustの型推論の動作を詳細に把握しているわけではない。 短くまとめると Rustの型推論はHindley-Milner型推論ベースである。したがって後方の式や文の内容から手前の型が推論されることもある。しかし以下に挙げるようなRust独自の特徴をもつ。 型推論は原則として関数定義の中で閉じており、関数の引数型や戻り値型は推論されない。これは、関数を抽象化の境界とするための意図的なものである。この意味で「局所的」というのであれば間違いではない。 ただし、let多相を含む型推論を避ける意図もあるかもしれない。 関数呼び出しや一部の演算子などは、その部分の制約を立てる段階で、型の一部分が判明している必要がある。この動作は推論順序の影響を受ける。 トレイトによりオーバーロード可能になっている関数や演算子は、射影型を使っている場合、ボトムアッ

    Rustの型推論の概略 - 簡潔なQ