読者です 読者をやめる 読者になる 読者になる

日本語が不自由な緑の箱の日記

主にD言語とロボコンを

カメノテ食べました

今日は自転車で結果的に海に行きました。岩場で大量のカメノテを見つけ、食べれると聞いたので少量頂いて帰りました。 f:id:namachan10777:20170416230550j:plain 食べようと思うには少しアレな見た目をしていますが、味は普通に貝のような何かで美味しいです。綺麗に岩から剥がした場合、そのまま茹でると岩に張り付いている筋肉の部分を覆う皮が旨味を完全に閉じ込めます。塩ゆでで食べるには問題ないですが出汁目当てで味噌汁に入れるなら先に皮を破いておくなりしないとダメだと思います。f:id:namachan10777:20170416231805j:plain (上が中身)

黒いエラのような部分はプランクトンを捉える蔓脚でシャリシャリするので除けて食べてもいいかもです。 カメノテは甲殻類ミョウガガイ目に属しており、どちらかと言うとカニやエビ、フジツボなどの仲間です。同じ固着生物で甲殻類のフジツボフジツボ亜目に属しており、こちらは蔓脚を使うカメノテと違い二枚貝に近い餌の取り方をしてるそうです。

とりあえず味噌汁にしてみましたが、量が少なかったのかカメノテの肉は美味なもののあまり出汁が出ませんでした。次は塊で採りたいです。

関東ではブームの際に資源が減少したりしたようなので採りすぎないように注意が必要です。

M570tをベアリング化しました

Ligicool社製の親指トラックボール、M570tを暫く使っていたのですが時々ボールの動きが物凄く渋くなることがあったためアルミナの支持球をベアリングに置き換えてみました。

kirmav.blogspot.jp

部室に転がってた外形Φ7のベアリングを使い、この方の記事を参考にして改造したのですがベアリングの軸は外側から付けたほうが良さそうです。穴は大きめに開ける必要がありますが、ベアリング軸固定用の溝は結構浅めにしないと組み立てた時にボールが入らなくなります。流石にΦ7のベアリングを入れると結構干渉する部品が多くなり色々な場所を削らないと入らなくなります。

感想

ベアリングを使ったので引っかかりは殆ど無くなるだろうと期待していたのですが、新品M570tより少し小さいぐらいでした。動摩擦も格段に下がってるので結局差がそこまで埋まらなかったのかもしれません。あと動かしてると僕の場合だけかもですが何故かガタガタ言います。操作性にはあまり影響してないのですが、少し気にならないでもないです。

結果としてはかなり満足なのですが必要な工具が結構多いためやろうとすると費用が結構厳しいです。ベアリングの単価はそこまで高く無いんだしベアリングトラックボールを公式で発売してほしいと言う感情が非常に強くなりました。あとベアリングと光学式読み取り器があればトラックボールは作れるようなので光学式読み取り装置さえどうにか出来れば自作トラックボールはマウス以上に簡単にできそうです。M570tの玉はAmazonで売ってますし。

D言語の動的配列について

メモです

int[] darray = [1,2,3];
int[3] sarray = [1,2,3];

pragma(msg,typeof(darray));    //当然int[]
pragma(msg,typeof(darray[]));  //int[]
pragma(msg,typeof(sarray));    //当然int[3]
pragma(msg,typeof(sarray[]));  //int[]

静的配列でも識別子に[]を付けると動的配列に変換することが出来ます。 また、スライス演算sarray[1..2]などでも動的配列が返ります。

ベクトル演算では静的配列でも動的配列でも同じようにarray1[] + array2[]と書きますが、動的配列の場合の[]は単なる構文なのに対し、静的配列の場合は前述の動的配列への変換も含まれているようです(多分)。

最近

Majestouchを使ってて手首が痛くなったのでパームレスト高専近くのホームセンターで買ってきた桧で作りました、手首が痛くならなくなって快適になりました。

Hoi4を買ってしまって時間が無限に融けました。生活リズムが崩壊して昼過ぎに起きるようになりました。

void[]

D言語にはvoidという関数やメソッドの返り値の型に指定することが出来る値を持たない型があります。void*という何のポインタかは分からないがとりあえずポインタであることを示す型があります。そして、void[]と言う狐につまさたような型があります。 dlang.orgには次のように記述されています。

原文

There is a special type of array which acts as a wildcard that can hold arrays of any kind, declared as void[]. Void arrays are used for low-level operations where some kind of array data is being handled, but the exact type of the array elements are unimportant. The .length of a void array is the length of the data in bytes, rather than the number of elements in its original type. Array indices in indexing and slicing operations are interpreted as byte indices.

void main()
{
    int[] data1 = [1,2,3];
    long[] data2;

    void[] arr = data1;            // OK, int[] implicit converts to void[].
    assert(data1.length == 3);
    assert(arr.length == 12);      // length is implicitly converted to bytes.

    //data1 = arr;                 // Illegal: void[] does not implicitly
                                   // convert to int[].
    int[] data3 = cast(int[]) arr; // OK, can convert with explicit cast.
    data2 = cast(long[]) arr;      // Runtime error: long.sizeof == 8, which
                                   // does not divide arr.length, which is 12
                                   // bytes.
}

Void arrays can also be static if their length is known at compile-time. The length is specified in bytes:

void main()
{
    byte[2] x;
    int[2] y;

    void[2] a = x; // OK, lengths match
    void[2] b = y; // Error: int[2] is 8 bytes long, doesn't fit in 2 bytes.
}

While it may seem that void arrays are just fancy syntax for ubyte, there is a subtle distinction. The garbage collector generally will not scan ubyte arrays for pointers, ubyte being presumed to contain only pure byte data, not pointers. However, it will scan void arrays for pointers, since such an array may have been implicitly converted from an array of pointers or an array of elements that contain pointers. Allocating an array that contains pointers as ubyte[] may run the risk of the GC collecting live memory if these pointers are the only remaining references to their targets.

意訳

これは任意の配列を取るための特殊な型で、void[]と宣言されます。void[]は配列の要素の値が重要でない場合に低レベルな配列の操作をする際に使われます。.lengthプロパティは元の型の配列での.lengthの値ではなく、その配列のbyteでの大きさを返します。void[]でのインデックスアクセスやスライスはbyteの配列に対するそれらの操作として解釈されます。

void main()
{
    int[] data1 = [1,2,3];
    long[] data2;

    void[] arr = data1;            // OK, int[]はvoid[]に暗黙の返還が出来る.
    assert(data1.length == 3);
    assert(arr.length == 12);      // .lengthは暗黙にbyteのものとして扱われる.

    //data1 = arr;                 // 不正な操作 : void[]はint[]に暗黙に変換できない.
                                   // int[]に変換。
    int[] data3 = cast(int[]) arr; // OK, 明示的なint[]への変換は出来る.
    data2 = cast(long[]) arr;      // Runtime error: longのサイズは8バイトであるため、
                                   //12バイトのvoid[]をうまく分割出来ないため 
                                   //ランタイムエラーになる. 
}

void[]コンパイル時にその長さが判明しているならば、void[12]のように静的配列にすることも出来ます。

void main()
{
    byte[2] x;
    int[2] y;

    void[2] a = x; // OK, 同じ長さ.
    void[2] b = y; // Error: int[2]の大きさは8バイトなので2バイトのvoid[2]には変換できない.
}

void[]ubyte[]はちょっとした構文上の違いのようですが、微妙な違いがあります。ubyte[]は純粋なバイト列のデータとみなされるために、GCのスキャンの対象となりません。しかし、void[]はポインタを含む任意の配列から変換された可能性がある為、GCののスキャンの対象となります。つまり、ubyte[]だとそこに何か生きているデータへのポインタが含まれていた場合に、もしそのポインタ以外の参照が無ければGCに回収されてしまうリスクが出来てしまうということです。

問題点

このvoid[]任意の型TにおけるT[]から暗黙に変換できてしまうと言うのが中々の曲者で、場合によっては予想外の動作を引き起こします。

例えば、再帰を使って各要素をそれぞれ2乗するコードです。

import std.stdio;

void main() {
    [1,2,3].square.writeln;
}

auto square(int[] ary) {
    if (ary.length == 0) return [];
    return [ary[0] ^^ 2] ~ square(ary[1..$]);
}

このコードを実行すると僕の環境では[1, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0]と言う結果が得られます。 この関数squareでは2つのreturn文が存在します。まず、[]はvoid[]なので、片方の型はvoid[]です。そしてreturn [ary[0] ^^ 2] ~ square(ary[1..$]);の型はint[] ~ typeof(square([334/+適当+/])の結果となります。int[] -> void[]への暗黙の変換は出来ますが、void[] -> int[]への暗黙の変換は出来ないのでsquareが返す値の型はvoid[]と推論されてしまいintの配列ではなく結果のバイト配列を返します。x86はリトルエンディアンの為、1,2,3はそれぞれ[1,0,0,0],[4,0,0,0],[9,0,0,0]で表されるバイト列に変換されます。

この場合は[]int[]にcastするか、返り値の型をint[]と明示してやれば[1,4,9]と期待通りの結果が得られます。

Fcitxに手こずったArch再インストール

少し早めの大掃除とPCにArch Linuxクリーンインストールしました。 /rootと/varを大きめに取り、swapパーティションを設定しgnomeを入れたまでは良かったのですがfcitxが変な挙動をするようになっていました。

fcitx-gtk3を使うと、アドオンのFcitx XIM Frontendが有効化されていると左下に変換パネルが表示されてしまい、無効化すると変換が確定するまでテキスト入力エリアに表示されない、変換途中で文字を入力し直すなどすると意図してない文字が入力されるなどの症状ができるようになりました。

適当に何度かアドオンの組み合わせを変更してみましたが一向に改善する気配がなかったのでfcitx-gtk3をアンインストールしfcitx-gtk2に切り替えると問題なく動作するようになりました。

なぜgtk3だとダメなんだ...

D言語のオフラインドキュメントのビルド

人権がない(十分に高速なインタネット環境が無い)場合でもD言語のドキュメントが読めるようにビルドしておく方法です。

git clone https://github.com/dlang/dlang.org
cd dlang.org
# LATEST=の部分は適宜バージョンに合わせて読み替えてください。
make -f posix.mak LATEST=2.072.0 docs

実行するとカレントディレクトリ内のwebディレクトリにビルドされたdlang.orgが出来ています。あとはその中身だけ適当なディレクトリに移し替えてcloneしてきたdlang.orgのローカルリポジトリを削除すれば良いだけです。 マルチコアCPUの場合はmakeする際に-jオプションを付けて並列化するとビルドが早くなり嬉しいかもしれません。

修正

make -f posix.mak LATEST=2.072.0 html

ではphobosのドキュメントがビルドされないようです。