ごらくらいふ

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

手紙を書くつもりでとんだ夢物語を書いた

ご無沙汰しております。

お元気にお過ごしでしょうか。 この、春にかけての季節は活力を落としがちで、心身の健康を心配しております。 かくいう私もめっきりアニメを嗜むこともできず、衰えを感じる日々でして、身体の方から健康にしていこうと運動を試みております。

つい先日、痩けた獣にわずかばかりの食事をあたえたところ、しきりに訪れては同じところを掘り返すようになりました。 いよいよ気になり一緒になって掘り返したところ温泉が吹き出し、さらには金の粒が次々とあふれ、あれよあれよと億はくだらない資産と相成りました。

いまは湯屋を営んでおります。 大変お世話になりました恩返しというほどではございませんが、往復の代金を同封させていただきました。 ぜひ一度お越しください。


みたいな。

Rustでホームディレクトリのファイルを読み込みたい(ドキュメントに書いてあってうれしかった話)

これ。

use std::env;
use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::prelude::*;

fn open_file() {
    let mut path = env::home_dir().unwrap();
    path.push("config.toml");

    let mut file = File::open(path).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    println!("body: {}", cotnents);
}

エラー処理は各々おねがい。

以下駄文(経緯ともいう)

ホームディレクトリ知りたいな。環境変数からかな。

お、標準ライブラリにそれっぽいのあるぞ。

std::env - Rust

むしろホームディレクトリ直通の関数があるぞ…素晴らしか。

std::env::home_dir - Rust

なるほどPathBufを返却するのかー。

ファイル名の追加はどうしたら良いんだろう。と思ったらPathBufのトップに書いてある…最高か。

std::path::PathBuf - Rust

じゃああとはファイル読み込みか。fsモジュールっぽいよね。

あ~~トップに答え書いてある~~~すき~~~。

std::fs::File - Rust

標準ドキュメント素晴らしい。これで私はconfigを得ました。(あとtomlをデシリアライズしたりしてる。)

Zaif-api-rust v0.5.0をリリースした。trait From、エラーハンドリングに便利だった。

ついさっき、Rustで書いたzaif-apiのwrapper、v0.5.0をリリースした。

github.com

今回の改修はエラーハンドリングが目的で、「まず動く」で作っていたところを取り回しできるようにした。

活躍したのが標準ライブラリに入っているFrom<T>トレイトで、あるstructがこれを実装するということは、特定の型から変換できると宣言することになる。

fn dl_and_parse (loader: http::Downloader, parser: parse::Parser) -> Result<Parsed, parse::Error> {
    // ダウンロード処理
    let text = downloader.fetch().unwrap().text().unwrap();
    // パースして返す
    parser.from_text(text)
}

まず動くものとしてこういうものを書いた。 これだと、downloader.fetch()で問題があった場合などにpanicを起こしてしまう。

落ちないようにErrを返してあげたいが、httpcrateがparseのErrorを持っていないので、単純にunwrapを?に書き換えただけではコンパイルエラーになってしまう。

これを解決するのが、Fromトレイト。 これを実装することで異なる型に馴染むことができる。

とはいえ、よそのcrateのErrorをまた別のcrateのErrorに差し込むのは流石に行儀が悪いので、Enumを用意して各crateのerrorを包むだけにした。 (それに、自分で丁寧なエラーハンドリングをしなくて良いので。)

enum MyError {
    HttpError(http::Error),
    ParseError(parse::Error),
}

impl From<http::Error> for Error {
    fn from(err: http::Error) -> Self {
        Error::HttpError(err)
    }
}
impl From<parse::Error> for Error {
    fn from(err: parse::Error) -> Self {
        Error::ParserError(err)
    }
}

これにより、unwrap()を排除しつつ、panicを起こさずに異常を伝えられるようになった。

fn dl_and_parse (loader: http::Downloader, parser: parse::Parser) -> Result<Parsed, MyError> {
    // ダウンロード処理
    let text = downloader.fetch()?.text()?;
    // パースして返す
    Ok(parser.from_text(text)?)
}

参考リンク

RustでOption値やResult値を上手に扱う - Qiita : https://qiita.com/tatsuya6502/items/cd41599291e2e5f38a4a

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秒待てば実行可能だった。