Hatena::ブログ(Diary)

bettamodokiのメモ このページをアンテナに追加 RSSフィード

"betta" means Siamese fighting fish (Betta splendens)
and "modoki" means resemblance or imitation in Japanese. So what?

2018-01-25

何も考えずにRustに入門する1

15:29 |  何も考えずにRustに入門する1を含むブックマーク  何も考えずにRustに入門する1のブックマークコメント

Bash on Ubuntu on Windows (Windows 10)でやる.

とりまインストールから.

sudo apt-get install rustc cargo

実行可能アプリケーションのプロジェクトをおもむろに作成して実行する.

~$ cargo new bar --bin
     Created binary (application) `bar` project
~$ cd bar/
~$ cargo run
   Compiling bar v0.1.0 (file:///home/foo/bar)
    Finished dev [unoptimized + debuginfo] target(s) in 1.31 secs
     Running `target/debug/bar`
Hello, world!

何もしなくてもとりあえずハローが出る. ソースファイルは"src/main.rs"に, 実行ファイルは"target/debug/bar"に作成される.

何も考えずにRustに入門する2

16:03 |  何も考えずにRustに入門する2を含むブックマーク  何も考えずにRustに入門する2のブックマークコメント

つづいてログメッセージを出力できるようにする. そのためにはまず依存するクレートCrateを宣言して読み込む必要がある.

まずは"Cargo.toml"の依存関係に"log"と"env_logger"を追加する.

[dependencies]
log = "*"
env_logger = "*"

あとはコードでこれらを呼び出す. 例えば"src/main.rs"を以下のように書き換える.

#[macro_use] extern crate log;
extern crate env_logger;

fn main() {
    env_logger::init();

    debug!("This is a debug message.");
    error!("This is an error message");
    println!("Hello, world!");
}

これで"cargo run"すると"ERROR"ではじまるメッセージと"Hello, world!"が出力されるはずだ. 別に"RUST_LOG=debug ./target/debug/bar"などとすると, "DEBUG"行も出力されるようになる.

何も考えずにRustに入門する3

16:26 |  何も考えずにRustに入門する3を含むブックマーク  何も考えずにRustに入門する3のブックマークコメント

"main"から呼び出す自前の関数はクレートとして分けておきたい. ライブラリとして切り出せそうなものは"main.rs"とは別のファイルにまとめることにする.

まず, "src/lib.rs"というファイルを作成し, 自前の関数などはこちらに記述する. 上の例の場合,

#[macro_use] extern crate log;

pub mod example {
    pub fn hello() {
        debug!("This is a debug message.");
        error!("This is an error message");
        println!("Hello, world!");
    }
}

クレートの中にモジュール"example"を作成し, その中で"hello"関数を作成した. これを"src/main.rs"から呼び出すには,

extern crate env_logger;

extern crate bar;
use bar::example;

fn main() {
    env_logger::init();

    example::hello();
}

何も考えずにRustに入門する4

16:49 |  何も考えずにRustに入門する4を含むブックマーク  何も考えずにRustに入門する4のブックマークコメント

Rustにはそもそもユニットテストフレームワークがあるようだ. "cargo test"とするとテストが実行される.

今回は自前で"src/lib.rs"を用意したので, このままだと何もテストされない. というわけでユニットテストを書いてみる.

#[macro_use] extern crate log;

pub mod example {
    pub fn hello() {
        debug!("This is a debug message.");
        error!("This is an error message");
        println!("Hello, world!");
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn test_hello() {
            hello();
        }
    }
}

"#[test]"をつけるとテスト時に呼び出されるようになる. このテストでは"hello"の中で"panic!"が呼ばれないことを確認する. あとは"assert!"なり"assert_eq!"なりをがしがし書いていけば良い.

何も考えずにRustに入門する5

18:34 |  何も考えずにRustに入門する5を含むブックマーク  何も考えずにRustに入門する5のブックマークコメント

Rustではソースコード中のコメントからドキュメントを作成できる.

"cargo doc"コマンドがそれだが, 上の例だと"error: cannot document a package where a library and a binary have the same name. Consider renaming one or marking the target as `doc = false`"と言われて怒られる. これは実行可能ファイルとライブラリが混在しており, 名前が同じためおこる. そこで以下のように"Cargo.toml"に追記して, 実行可能ファイルの呼び名をかえて, ドキュメントの生成もしないようにする.

[[bin]]
name = "main"
doc = false
path = "src/main.rs"

これでドキュメントの生成が可能になったのであとはコメントを追加していく.

pub mod example {
    //! This is a module as an example.

    /// Displays a message.
    ///
    /// # Examples
    ///
    /// ```
    /// # use bar::example;
    /// example::hello();
    /// ```
    pub fn hello() {
        println!("Hello, world!");
    }
}

"//!"はそれを囲むモジュールの説明であり, "///"はそれにつづく関数の説明になる.

"```"で囲むことでコードを埋めこむことができる. コードスニペット中の"#"以下の行は実行はするがドキュメント上は見せないという意味になる. このコードはドキュメントとしてだけでなく, "cargo test"としたときに実際に実行されテストにかけられる. これを記述した上で先のように"cargo test"すると"Doc-tests"のところでテストが行なわれていることがわかる.

ひとつ注意として, 上のコードで"use bar::example;"としているが, この前に"extern crate bar"などとしてはいけない. その行があると, "error[E0432]: unresolved import `bar`" "Maybe a missing `extern crate bar;`?"というあべこべなエラーになる. これはむしろ"extern"していることで生じたエラーのようだ.

https://github.com/rust-lang/rust/issues/39341

2017-10-30

Windows 10のBash on Ubuntu on WindowsでPython 3.6

01:24 |  Windows 10のBash on Ubuntu on WindowsでPython 3.6を含むブックマーク  Windows 10のBash on Ubuntu on WindowsでPython 3.6のブックマークコメント

Pyenvで入れるのが楽そうだったが, Pyenvを使うのが初めてだったため少しはまった. Pyenv自体は以下で入る.

$ curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

最後にメッセージが出てくる通り, .bashrcにでも以下のように書いてパスを通しておくと良い.

export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

と, ここで依存するライブラリをインストールせずに環境をインストールするとはまる. インストール自体は成功するのだがいざ動かすと一部のエラーで落ちる. "ModuleNotFoundError: No module named '_bz2'"とか, matplotlibを使うときに"ModuleNotFoundError: No module named '_tkinter'"とか.

ちゃんと

apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev

をしてからインストールすること. 既にインストールしていた場合はアンインストールしてやりなおさなければならない.

# $ pyenv uninstall 3.6.3
$ pyenv install 3.6.3
$ pyenv global 3.6.3

以下の記事をちゃんと読めば書いてあった.

https://qiita.com/mogom625/items/b1b673f530a05ec6b423

https://github.com/pyenv/pyenv/wiki

2017-06-05

C++のif条件式の中での変数宣言

12:21 |  C++のif条件式の中での変数宣言を含むブックマーク  C++のif条件式の中での変数宣言のブックマークコメント

dynamic_castを利用する際に以下のように書く場面が出てくる.

Base* base = new DerivA();

if (DerivA* derivA = dynamic_cast<DerivA*>(base))
{
  ; // do something with derivA
}

if (DerivB* derivB = dynamic_cast<DerivB*>(base))
{
  ; // do something with derivB
}

この場合, 二度目のdynamic_castは失敗するため, if文の中身も実行されない.

しかし, 実際のところこれはこの宣言式の何を判断しているのか? この記法について書いている人は多かったのだがそれを説明している人は少なさそうだったので調べてみた. 規格書(?)*1を確認してみると

condition:
      expression
      attribute-specifier-seqopt decl-specifier-seq declarator = initializer-clause
      attribute-specifier-seqopt decl-specifier-seq declarator braced-init-list

となっており, 確かに変数宣言が許可されている(p.125). ちなみにだが, parenthesized initializerは許可されていない. DerivA* derivA(dynamic_cast<DerivA*>(base))とは書けない.

では, 判定はどうなっているかというと, 皆様ご想像の通り,

The value of a condition that is an initialized declaration in a statement other than a switch statement is the value of the declared variable contextually converted to bool (Clause 4). If that conversion is ill-formed, the program is ill-formed.

switchで使う場合以外は, declarator(上で宣言された変数)をboolにキャストしてその値を使う, とある. キャストできない変数の宣言は許されない. というわけで, dynamic_castが成功した時だけ実行されるのは, dynamic_castが失敗したときにnullptrを返し, nullptrはbool値としてはfalseになるためである.

単にスコープの目的だけでここに変数宣言することは意味もないし危険である.

if (int x = 1)
{
  ; // play with 1
}

if (int x = 0)
{
  ; // play with 0
}

二つ目のif文の中身は実行されない. こんなん間違えないよ, という人もいるかもしれないが, この記法について調べたときには以下のような例がわんさと出てきた.

if (double x = some_function(y, z))
{
  ; // this works only if x is not zero.
}

これを意図的に使えないこともない*2が, はっきり言って僕は分かりにくいと思うのでポインタ以外では使わない方が良いのではないか.

*1http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

*2:独自のクラスでboolへのキャストを実装しておくとか

2017-05-31

Cythonで'bool' is not a constant, variable or function identifier

12:31 |  Cythonで'bool' is not a constant, variable or function identifierを含むブックマーク  Cythonで'bool' is not a constant, variable or function identifierのブックマークコメント

Cythonである変数がbool型であるかを調べるのに"isinstance(val, bool)"のようにしたところ, "'bool' is not a constant, variable or function identifier"と怒られた.

どうも, Cythonで扱うbool型には二種類あるらしく*1, libcppのboolを用いているとこのエラーが出る. Pythonにおけるbool型を得たい場合はcpythonのものを利用するようにすれば良い.

from libcpp import bool
from cpython import bool as bool_t
val = True
if isinstance(val, bool_t):
    do_something(<bool> val)

https://github.com/cython/cython/wiki/FAQ#how-do-i-declare-an-object-of-type-bool

*1:bintも加えれば3種類.

2017-02-16

KinesisキーボードでCtrl, Alt/Option, Windows/Commandがおかしなことになったとき

18:22 |  KinesisキーボードでCtrl, Alt/Option, Windows/Commandがおかしなことになったときを含むブックマーク  KinesisキーボードでCtrl, Alt/Option, Windows/Commandがおかしなことになったときのブックマークコメント

どうすれば良いかが下のページに書いてある.

https://www.kinesis-ergo.com/support/technical-support/troubleshoooting-advantage/

"=w", "=m", "=p"のいずれかを同時押しするとキーボードのモードが変わるらしい. 時々気が付かずにやらかすのでメモ.

Connection: close