/tmp
に書けばよかったんや
vim /tmp/draft.md
/tmp
に書けばよかったんや
vim /tmp/draft.md
Rust製のZaif API Wrapperを作っているので、これをコマンドラインツールとして使用するCrateを作成した。
RustとCargoの準備が整っているなら、以下のコマンドでインストールできる。
cargo install zacli
通貨ペアを確認したり
$ zacli currency_pairs all | grep zaif
currency_pair: zaif_jpy
currency_pair: zaif_btc
板情報を確認したり
$ zacli depth zaif_jpy
type price amount
ask 1.01 15000.0
ask 1.02 500.2
...
bid 1.005 12000.0
bid 1.0048 450.5
注文できます。
$ zacli trade zaif_jpy bid 1.0 100
https://crates.io/crates/zacli
要望とかあったらissue, P-r待ってます。
ご無沙汰しております。
お元気にお過ごしでしょうか。 この、春にかけての季節は活力を落としがちで、心身の健康を心配しております。 かくいう私もめっきりアニメを嗜むこともできず、衰えを感じる日々でして、身体の方から健康にしていこうと運動を試みております。
つい先日、痩けた獣にわずかばかりの食事をあたえたところ、しきりに訪れては同じところを掘り返すようになりました。 いよいよ気になり一緒になって掘り返したところ温泉が吹き出し、さらには金の粒が次々とあふれ、あれよあれよと億はくだらない資産と相成りました。
いまは湯屋を営んでおります。 大変お世話になりました恩返しというほどではございませんが、往復の代金を同封させていただきました。 ぜひ一度お越しください。
みたいな。
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); }
エラー処理は各々おねがい。
お、標準ライブラリにそれっぽいのあるぞ。
むしろホームディレクトリ直通の関数があるぞ…素晴らしか。
なるほどPathBuf
を返却するのかー。
ファイル名の追加はどうしたら良いんだろう。と思ったらPathBuf
のトップに書いてある…最高か。
じゃああとはファイル読み込みか。fsモジュールっぽいよね。
あ~~トップに答え書いてある~~~すき~~~。
標準ドキュメント素晴らしい。これで私はconfigを得ました。(あとtomlをデシリアライズしたりしてる。)
ついさっき、Rustで書いたzaif-apiのwrapper、v0.5.0をリリースした。
今回の改修はエラーハンドリングが目的で、「まず動く」で作っていたところを取り回しできるようにした。
活躍したのが標準ライブラリに入っている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
を返してあげたいが、http
crateが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)?) }
trait From「彼なら、僕になれる」
— 華夜 (@Yajamon) 2018年3月2日
trait Into「僕なら、彼になれる」#rust #rustlang
RustでOption値やResult値を上手に扱う - Qiita : https://qiita.com/tatsuya6502/items/cd41599291e2e5f38a4a
ダイナミックリンクライブラリと読む。 動的なリンクで利用されるライブラリ。
リンクというものは、以下の認識でいる。
中でも静的リンクライブラリは、プログラムの中に直接つなぎこまれるモノを言う認識。 それ故にプログラムは単体で完結できるが、複数のプログラムで、まったく同じ処理が存在することがある。 これがリソースの無駄遣いに繋がる。
https://support.microsoft.com/ja-jp/help/815065/what-is-a-dll より
コードのモジュール化、コードの再利用、メモリ使用の効率化、ディスク領域の削減が促進されます。 これにより、オペレーティング システムおよびプログラムの読み込みや実行が速くなり、コンピュータ内で占めるディスク領域が小さくなります。
また、以下のメリットが挙げられている。
「処理」と「処理の開始点」のつなぎ込みで、以下の違いが現れる。
あるプログラム片の処理から、あるプログラム片の処理の開始点へ移動する際
動的リンクの利点はわかったけれど、結局アプリケーションを配布する時にDLL同梱してない? リソースが少ない利点を享受しているの、.NET Framworkくらいなのでは…
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; } }
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); }