turbofish syntax(@Rust)

https://doc.rust-jp.rs/rust-by-example-ja/expression.html

にturbofish構文(syntax)というのが出てきて何なのかと思ったら、形(::())からきているらしい。なぜ::をつけないといけないかと言うと、::無しだと関数の呼び出しと区別できないから。

以下のコードはオリジナルから多少変えてあって、ブロックに書き直しています。この方が読みやすくなると感じるから。

fn main() {
    // string -> integer
    let sum = {
        let parsed: i32 = "5".parse().unwrap();
        let turbo_parsed = "10".parse::().unwrap();    // turbofish syntax

        parsed + turbo_parsed
    };
    println!("Sum: {:?}", sum);
}

 

admin

 

ドライケース

フィラメントの吸湿対策で、フィラメントヒーターは設備しましたが一度吸湿したものを乾燥させるのは時間もかかるし、完全には元に戻らないらしいし。

でおそらく定番だろう、保管用のドライケースを昨年12月に購入して3ヶ月程度保管してみましたが効果はあるようです。まあ冬場だったので本格的に評価できるのは夏場になりますが。

目安の湿度計は最初から付属していて、イエローの領域が望ましいらしいですが、シリカゲルではせいぜいイエローとブルーの境界ぐらいまでしか落ちません。

新しいフィラメントを買ったら、強力乾燥剤というのを一緒に入れてみようと思う。

https://www.amazon.co.jp/dp/B07Q95DRLP/?coliid=ICZNPUHJZCCXL&colid=3GQTE1XFD2G9Z&ref_=list_c_wl_lv_ov_lig_dp_it&th=1

3Dプリンターの運用周りでは、これで概ね完了のように思います。

 

 

admin

ホバークラフトVer2に取り掛かる

第一目標は、構造のアンバランスによる回転力を極力抑えてccw/cwプロペラの回転差で回転をコントロールできるようにすること。そのためには取り付けを正確にしないといけないからプロペラ部分を独立造形で微調整も可能にしたつもり。

あと一点は空気の抜けを良くするために、障害物となるリブをコンパクト化して写真の左(Ver1)、右(Ver2)のようにしてみた。

 

プロペラの回転数差で回転を制御できれば、micro:bitのコンパス情報を使って回転方向のドリフトを抑えることが可能になるだろう。

そのためにはmicro:bitを水平実装しないといけないからベース部も作り直し。

2024/3/22 追加

こんな感じで重量バランスは考慮してmicro:bitを配置して、レギュレータは軽量化のため両面テープで貼り付け。Ver1が300グラム超過だったものが合計で数十グラムは軽量化になると予測。

 

admin

 

 

 

Fromトレイト(@Rust)

https://doc.rust-jp.rs/rust-by-example-ja/conversion/from_into.html

に以下のFromトレイトを使ったユーザ定義型の型変換サンプルコードが出てきますが、お馴染みのString::fromもString型に対して(impl From<&str> for String {~~途中省略~~})とfromを定義しているのでやっていることは同じ、

use std::convert::From;

#[derive(Debug)]
struct Number {
    value: i32,
}

impl From for Number {
    fn from(item: i32) -> Self {
        Number { value: item }
    }
}

fn main() {
    let num = Number::from(30);
    println!("My number is {:?}", num);
}

std::convert::Fromトレイトは、

pub trait From: Sized {
    // Required method
    fn from(value: T) -> Self;
}

のようになっているので、from()にこの例のように個別の実装(impl From for Number)をしてやれば、自作の型でも型変換ができるようになります。

 

admin

 

 

refパターン(@Rust)

https://doc.rust-jp.rs/rust-by-example-ja/custom_types/enum/testcase_linked_list.html

のコードでrefと&で何が違うのと思ったのですが、

Rust by exampleの以下のページに出てくるrefパターン

https://doc.rust-jp.rs/rust-by-example-ja/scope/borrow/ref.html

の解説は、

—————————-

 // 左辺に`ref`をつけることによる借用と、右辺に`&`をつけることによる借用は等価

    let ref ref_c1 = c;

    let ref_c2 = &c;


ということなので、どちらも借用ですが似てるようで意味は全く異なります。

該当部分のコード全体をいかに再掲(長ったらしいので日本語は削除)しますが、タプル全体の文字列と長さの取得処理は再帰処理を使っています。

https://doc.rust-jp.rs/rust-by-example-ja/custom_types/enum/testcase_linked_list.html

use crate::List::*; // equivalent to following two lines, it's a short form of the enum List 
//use crate::List::Cons;
//use crate::List::Nil;

#[derive(Debug)]
enum List {
    // Cons: Tuple struct that wraps an element and a pointer to the next node
    Cons(u32, Box 	 	 	),
    // Nil: A node that signifies the end of the linked list
    Nil,
}

// Methods can be attached to an enum
impl List {
    // Create an empty list
    fn new() -> List {
        // `Nil` has type `List`
        Nil
    }

    // Consume a list, and return the same list with a new element at its front
    fn prepend(self, elem: u32) -> List {
        // `Cons` also has type List
        Cons(elem, Box::new(self))
    }

    // Return the length of the list(using recursive call)
    fn len(&self) -> u32 {
        // `self` has to be matched, because the behavior of this method
        // depends on the variant of `self`
        // `self` has type `&List`, and `*self` has type `List`, matching on a
        // concrete type `T` is preferred over a match on a reference `&T`
        // after Rust 2018 you can use self here and tail (with no ref) below as well,
        // rust will infer &s and ref tail. 
        // See https://doc.rust-lang.org/edition-guide/rust-2018/ownership-and-lifetimes/default-match-bindings.html
        match *self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            Cons(_, ref tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length
            Nil => 0
        }
    }

    // Return representation of the list as a (heap allocated) string(using recursive call)
    fn stringify(&self) -> String {
        match *self {
            Cons(head, ref tail) => {
                // `format!` is similar to `print!`, but returns a heap
                // allocated string instead of printing to the console
                //println!("st: {}, {}", head, tail.stringify());
                let ret: String = format!("{}, {}", head, tail.stringify());
                println!("{:?}", ret);
                ret
            },
            Nil => {
                format!("Nil")
            },
        }
    }
}

fn main() {
    // Create an empty linked list
    let mut list = List::new();

    // Prepend some elements
    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    // Show the final state of the list
    println!("linked list has length: {}", list.len());
    println!("{}", list.stringify());
}

コメントにあるように2018年版のRustからは*selfとref tailの*とrefは不要になった(&とrefを推論する)そうで、確かにそう変えてもコンパイルは通ります。となると、fn stringify(&self)も同じように書き換え可能なので、このソースでrefを使う必要はなくなりますが。

        match self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            Cons(_, tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length

 

admin

モジュール化(@Rust)

コードの記述が一個のファイルに収まるケースというのは現実にはほぼないので、モジュール構成が必要になりますが、以下は割と単純なケースになります。

最初は印字する関数print()だけのファイルmod_sample.rsがmain.rsと同じディレクトリに存在しています。

<mod_sample.rs>

pub fn print(arg: &str) {
    println!("{}", arg);
}

呼び出される関数はpublic(pub)でないとコンパイルエラーになります。

呼び出し側は、

<main.rs>

mod mod_sample;

fn main() {
    use crate::mod_sample::print;
    let msg = "hello";
    print(&msg);
}

Rustの場合にはmain.rs(バイナリクレートが複数あればそれぞれに)にmod文で呼び出すクレート名(mod_sample)を指定しておきます。use文はクレートの短縮形を指定しているだけで、本質ではありません。

一番シンプルにはこれだけですが、実際には呼び出される側が階層構造になっているケースが多いだろうと思われます。例えば以下のようなディレクトリ構成で、

ここで新たに現れるファイルがmod.rsで、これはこの名前でないとモジュールの検索ができません。

mod.rsの中身は他のクレートを定義しているだけですが、mod.rs経由でここで大義されたクレートを呼び出すわけです。呼び出されるmod_sample.rsには変更は不要です。

<mod.rs>

pub mod mod_sample;

クレートファイルが複数存在する場合にはそれらを列挙、最後にmain.rsにも変更が入ります。階層構造のルートディレクトリ名を指定するようにします。

<main.rs>

mod libra;

fn main() {
    use crate::libra::mod_sample::print;
    let msg = "hello";
    print(&msg);
}

 

admin

 

デストラクト(@Rust)

デストラクト(destructuring)は紛らわしいのですが、Rustの変数がスコープを外れた時に廃棄されるデストラクター(destructor)とは別物です。

ではデストラクトとは何かというと、

https://exercism.org/tracks/rust/concepts/destructuring

に記載あるように、タプルや構造体の要素の初期化です。

About Destructuring

Destructuring is the process of breaking down items into their component parts, binding each to smaller variables.

例えばタプルの初期化ならば、

Destructuring Tuples

Destructuring tuples is simple: just assign new variable names to each field of the tuple:

let (first, second) = (1, 2);

というふうに、機能的にはJavaScriptの分割代入 (Destructuring assignment) 構文と同じに見えます。

Rust by exampleでは、

https://doc.rust-lang.org/stable/rust-by-example/flow_control/match/destructuring.html

が公式ドキュメントです。

 

admin

構造体リテラル更新記法におけるString型(@Rust)

構造体のインスタンス作成時に、すでに作成済みのインスタンを使用するということですが、以下の例でdivの型をString型とするとコンパイルが通りません。

何故なら、divをString型にするとemp2で..emp1でdivを使用した瞬間に所有権がemp1からemp2に移動してしまうためです。数値はプリミティブ型なのでそのようなことは起きないのですが。

#[derive(Debug)]
struct Employee<'lt> {
    name: String,
    age: u8,
    grade: u8,
    div: &'lt str,
}

fn main() {
    let div: &str = "sales";
    let emp1 = Employee{name: String::from("John"), age: 30, grade: 3, div: div};
    let emp2: Employee = Employee{name: String::from("Bill"), age: 25, ..emp1};
    println!("{:?}, {:?}", emp1, emp2);
}

つまり構造体でフィールドとして参照を持つ場合、参照フィールドには必ずライフタイムが必要ということです。

以下のようにstatic宣言にしてプログラム実行中のライフサイクルにしても良いですが、永続的なライフタイムを持つすなわちメモリをずっと占有してしまいます。

struct Employee {
    name: String,
    age: u8,
    grade: u8,
    div: &'static str,
}

Rustでは所有権にまつわる規則がどこかで必ず現れてきます。

 

admin

 

 

電源オンオフスケジュール用のGUIがある時点から無くなってる(MacBook)

昔の設定がMacOSのアップデートで設定が引き継がれていただけですが、以前はGUIでリブート設定していたものが、今はコマンドラインで設定するように変わっていた。ずっと変えてなかったから気づいていなかったけど。

pmsetコマンドで現在の設定を見てみると、

@MacBook-Pro ~ % pmset -g sched
Repeating power events:
restart at 5:00AM every day

こんな感じになっているから、最後の行のパラメータをpmsetコマンドで打ち込めばいいんだろう。使い方は、

% man pmset

で見れます。

 

admin

 

 

 

マイクラEEでmaze

maze(迷路)の作成アルゴリズムには色々ありますが、一番単純なアルゴリズムが棒倒し法です。棒倒し法のアルゴリズムは他で参照していただくとして、それをマイクラEE(教育エディション)で実装してみます。bedrock版でもプラグイン使うとMakecodeと連携できるようですが、マイクラEEではデフォルトでcode builder(中身はMakecodeと同じに見えます)が使えますからエージェントに迷路を作成させてみます。

いきなりですが、作成した画像は、

こんな感じです。

動画版は、

code builderのソースは以下のリンクから、

https://minecraft.makecode.com/88632-58071-51947-80905

① 初期化処理(『最初だけ』)で周りの囲いと一つおきに棒(以下ブロック)の配置をするための配列(リスト)を作成、リストを二つ作るのはブロックの重複置きチェックのために倒したブロックの配置を記憶しておくためです

② チャットコマンド”maze”を入力したときに、最初に枠と棒倒しの基準になるブロックを置き、次に迷路作成のための”make_wall”を呼び出しています

③ make_wall中では最初のブロックと二番目以下のブロックでは倒せる方向の可能性が違うので、引数で処理を分けて実際の棒倒し処理(“random_block”)を呼び出します。

④ random_block中では乱数で倒す方向を決めて、もし倒す方向に既にブロックが存在していれば、他の倒し先を乱数で決定して倒しますが、この処理も最初のブロック列と二番目以下のブロック列では処理が異なるのでロジックを分けて記述必要です

簡単に書くとこのような処理を行なっていますが、code builderのブロック言語でそこそこ長いコードを記述すると、コードの見通しが良くないので、実際のロジックの検証はPythonあるいはJavaScriptに展開されてコードで行うのが現実的。あとデバッグ機能のようなものも存在しないのでそこが不便なのと、変数のスコープがいまいちすっきりしないので、関数へはsize(正方形のサイズ)以外は引数渡しにしてローカル変数のごとく使っています。

これ以上に複雑なmazeロジックの記述はおそらく大変、

 

admin