ごらくらいふ

プログラミングしたりゲームしたり

DLLってなんなのん

DLLとは

ダイナミックリンクライブラリと読む。 動的なリンクで利用されるライブラリ。

対義語: 静的リンクライブラリの認識

リンクというものは、以下の認識でいる。

  • プログラムは、複数のコンパイルされたマシン語のプログラム片(以下、プログラム片)から成る。
  • ひとつのソースコードコンパイルするとひとつのプログラム片が生成される。
  • このプログラム片には、「処理」「処理の開始点」「処理の終了処理(return等)」が含まれている
  • リンカーが、それぞれのプログラム片の「処理」と「処理の開始点」をつなぎこむ

中でも静的リンクライブラリは、プログラムの中に直接つなぎこまれるモノを言う認識。 それ故にプログラムは単体で完結できるが、複数のプログラムで、まったく同じ処理が存在することがある。 これがリソースの無駄遣いに繋がる。

動的リンク

解決する要素

https://support.microsoft.com/ja-jp/help/815065/what-is-a-dll より

コードのモジュール化、コードの再利用、メモリ使用の効率化、ディスク領域の削減が促進されます。 これにより、オペレーティング システムおよびプログラムの読み込みや実行が速くなり、コンピュータ内で占めるディスク領域が小さくなります。

また、以下のメリットが挙げられている。

  • 使用するリソースが少ない
  • モジュラー アーキテクチャが促進される
  • 配置およびインストールが容易になる

動的リンクと静的リンクの違い

「処理」と「処理の開始点」のつなぎ込みで、以下の違いが現れる。

あるプログラム片の処理から、あるプログラム片の処理の開始点へ移動する際

  • メモリ上のどの地点へ移動すればよいか、プログラム内で予め判明しているものが静的リンク
  • メモリ上のどの地点へ移動すればよいか、システムに問い合わせて判明するものが動的リンク

所感

動的リンクの利点はわかったけれど、結局アプリケーションを配布する時にDLL同梱してない? リソースが少ない利点を享受しているの、.NET Framworkくらいなのでは…

参考リンク

Rustの話: traitの定義部分では、フィールドに干渉できない

前提

rustc 1.22.1

本題

traitを書く時、こういう書き方はできない。

trait Horizontal {
    // x:i64 というフィールドの存在を前提とする
    // x をカウントアップして、新しい値を返す
    fn count_up (&mut self) -> i64 {
        self.x += 1;
        self.x
    }
}

struct Point {
    x: i64, // コンパイラにフィールドの追加を強制される
}
impl Horizontal for Point {}

前提としてtraitのデフォルト実装はフィールドに干渉できない。

Traitを実装したStructに特定のフィールドを強制したい場合、 例えば、getter/setterの定義を用意することで実現できる。

trait Horizontal {
    fn get_x (&self) -> i64;
    fn set_x (&mut self, val: i64);
    
    fn count_up (&mut self) {
        let next = self.get_x() + 1;
        self.set_x( next );
        self.get_x()
    }
}

struct Point {
    x: i64, // getter/setterのためにフィールドを用意する
}
impl Horizontal for Point {
    fn get_x (&self) -> i64 {
        self.x
    }
    fn set_x (&mut self, val: i64) {
        self.x = val;
    }
}

余談: getter/setterのマクロを書いてみた

traitで使うaccessorと、実装時に使うaccessor_impl

macro_rules! accessor {
    ((get=$getter:ident) : $type:ty ) => {
        fn $getter(&self) -> $type ;
    };
    ((set=$setter:ident) : $type:ty ) => {
        fn $setter(&mut self, value:$type) ;
    };
    ((get=$getter:ident, set=$setter:ident) : $type:ty ) => {
        accessor!((get=$getter): $type);
        accessor!((set=$setter): $type);
    };
}
macro_rules! accessor_impl {
    ((get=$getter:ident) $name:ident : $type:ty ) => {
        fn $getter(&self) -> $type {
            self.$name
        }
    };
    ((set=$setter:ident) $name:ident : $type:ty ) => {
        fn $setter(&mut self, value: $type) {
            self.$name = value;
        }
    };
    ((get=$getter:ident, set=$setter:ident) $name:ident : $type:ty ) => {
        accessor_impl!((get=$getter) $name:$type);
        accessor_impl!((set=$setter) $name:$type);
    };
}

このマクロを使うとこんな感じになる。フィールドが増えないと効き目が薄い。

trait Horizontal {
    accessor!((get = get_x, set = set_x): i64);
    fn count_up(&mut self) -> i64 {
        let next = self.get_x() + 1;
        self.set_x(next);
        self.get_x()
    }
}
struct Point {
    x: i64,
}

impl Horizontal for Point {
    accessor_impl!((get = get_x, set = set_x) x: i64);
}

Grepのオプション no-filename(-h) を使う時

grepコマンドのオプションに--no-filename(-h)というものがある。 これは、マッチした内容をファイル名、Pathのプレフィックスを除いて結果を出力してくれる。

単一ファイルの検索や、標準入力からの検索時には、デフォルトで有効となっている。

用途

複数のファイルから検索して、かつプレフィックスが邪魔になるケース。

たとえばObjective-Cで、import文を調査する時に活用できる。

grep "#import" -h -R src | sort | uniq

Zaif Apiに対する知見

Zaif Api v1.1.1 http://techbureau-api-document.readthedocs.io/ja/latest/index.html

Zaif APIを弄ってて得た覚え書き。

  • trade_api/active_ordersや、trade_api/cancel_ordercurrency_pairは任意項目となっているが、入力しないと挙動が安定しない。
  • ほぼ開発時のデバッグにしか影響しないが、trade_api/tradeの結果で得た注文のcancel_orderは、少なくとも5秒待てば実行可能だった。

Rustでzaif apiのwrapperを書いている

Rustでzaif apiのwrappreを書いている。

reqwestでもりもり実装していて、なんか楽しい。

まだ借用チェッカーと戦ってるボーイなので、もりもりコピーして構造体たち皆所有権のあるデータ持つ、みたいな書き方してる。 まぁ使う分には引数に与えたデータを延命させたりとか、そういう気を使わなくて良いんじゃないでしょうか。教えてくれ。

Crate

https://crates.io/crates/zaif-api

github.com

すげぇ

cargo publishするとcrate.ioに載って、Cargo.tomldependenciesに依存対象として書けるようになる。

驚いたのはDocs.rsに自動でドキュメントが出力されること。かしこい~~。

列挙型で error[E0507]: cannot move out of borrowed content に対処した

ムーブセマンティクスを忘れていた話。

Builderパターンで以下のように書いたところコンパイラerror[E0507]: cannot move out of borrowed contentと怒られた。

enum Method {
    Get,
    Post,
}
struct Client {
    method: Method,
}
struct ClientBuilder {
    method: Method,
}
impl ClientBuilder {
    fn new() -> Self {
        ClientBuilder {
            method: Method::Get,
        }
    }
    fn method(&mut self, method: Method) -> &mut Self {
        self.method = method;
        self
    }
    fn finalize(&self) -> Client {
        Client {
            method: self.method,
        }
    }
}

ClientBuilder.finalize()で、self.methodの所有権を失ってしまうために怒られていた。

対応

列挙型MethodCopyトレイトを実装することで解決できる。そのためのアトリビュートもある。

#[derive(Copy, Clone)]
enum Method {
    Get,
    Post,
}

認識の修正

この対処方法はドキュメントにも書いてある

このケースは、以下の認識で書いたために引っかかってしまった。

  • enumの中身は数値だろう、すなわち、プリミティブな値だろう
  • プリミティブな値であればコピーされて所有権を失わないだろう

この認識を改めていく。

enumの中身はプリミティブな値ではない

ドキュメント 列挙型 より

列挙型の値(ヴァリアントと呼ぶ)は構造体の定義である。 Unit-like構造体であったり、名前付きフィールドを持つ構造体であったり、タプル構造体であったり。

enum Message {
    Quit,
    ChangeColor(i32, i32, i32),
    Move { x: i32, y: i32 },
    Write(String),
}

そもそもプリミティブな値だから所有権を失わないのではない

ドキュメント 所有権 より

全てのプリミティブ型は Copy トレイトを実装しているので、推測どおりそれらの所有権は「所有権ルール」に従ってはムーブしません。

Copyトレイトを実装しているから、所有権を失わない。

所感

見事にドキュメントで説明される事柄を踏み抜いた

ロッテリアのバーガーはレア物を店内で戴け

のびーるピザバーガー。これは良いものだった。もう食べちゃって写真すらないんだけれど、これは何かに書き残しておきたいと思ったのでセットドリンクを吸い上げながら執筆している。

注文して待つこと数分。座席に届いた限定バーガーは、身の丈が高い。モスバーガーに来たのかと思うほどだった。

齧る。前歯が温かくふっくらとしたバンズを裂き、ハッシュドポテトを削り、下の歯と協力して本命のチーズを断つ。滲むピザソースの塩気が舌に心地よい。

ついに口からバーガーを引き離した途端、チーズが、伸びたのだ。

伸びる。これがよく伸びる。唇で何度か手繰るもののまだ伸びる。 これは冷めたら大変だ固まってしまう。齧り、引き、噛み、また齧るサイクルを高速で繰り返し、すぐに完食した。

食べきって思う。やはりロッテリアのバーガーは新登場や期間限定品に限ると。店内だとなお良い。

まず温かく食べられる。そして何より型崩れしていない。もう一度言う、型崩れしていない。

絶品チーズバーガーもそうだった。今や哀愁すら感じる有様だが、登場したときは香ばしさすら感じるバンズ、滴らんばかりのチーズがもたらすはじめの一口は感動的ですらあった。

もしロッテリアに足を運ぶときが来たら限定商品を食べてみよう。新商品を食べてみよう。 ポテトのおかずではない、「あんたが主役」なバーガーと出会えるだろう。

C93を翌日に控えてポテトつまんでる現場からお送りしました。