associated function & method(@Rust)

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

のサンプルでsquareをtranslate()しただけで途中で結果の出力がないので補足、Pair部分はPoint ~~ Suareからは独立している部分になってます。

関連関数(associated function)はそのままの訳ですが、ここではPointという特定のタイプとだけ関連づけられていてselfを使っていないので、そのように呼ばれます。関連関数の本来的な意味からすると、horigin()、 new()の関連関数にはPointを使っていますが、本来的にはここではSelfを使うのが自然だろうと思う。

つまり引数にself(&mut self, &self)を取ればメソッド、selfでなくSelfを使うなら関連関数になります。

ここではメソッドは、構造体の文脈(ここでは構造体Rectangle)に関連づけられていて引数にはselfを使います。ここでrectangleとsquareという変数を作成していますが、交差する辺の長さが違うか同じかだけで、squareをmutableにすることでtranslate(ここでは平面移動)ができるようにしています。

// associated function & method
//
struct Point {
    x: f64,
    y: f64,
}

// Implementation block, all `Point` associated functions & methods go in here
impl Point {
    // This is an "associated function" because this function is associated with
    // a particular type, that is, Point.
    //
    // Associated functions don't need to be called with an instance.
    // These functions are generally used like constructors.
    fn origin() -> Point {
        Point { x: 0.0, y: 0.0 }
    }

    // Another associated function, taking two arguments:
    fn new(x: f64, y: f64) -> Point {
        Point { x: x, y: y }
    }
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    // This is a method
    // `&self` is sugar for `self: &Self`, where `Self` is the type of the
    // caller object. In this case `Self` = `Rectangle`
    fn area(&self) -> f64 {
        // `self` gives access to the struct fields via the dot operator
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        // `abs` is a `f64` method that returns the absolute value of the
        // caller
        ((x1 - x2) * (y1 - y2)).abs()
    }

    fn perimeter(&self) -> f64 {
        let Point { x: x1, y: y1 } = self.p1;
        let Point { x: x2, y: y2 } = self.p2;

        2.0 * ((x1 - x2).abs() + (y1 - y2).abs())
    }

    // This method requires the caller object to be mutable
    // `&mut self` desugars to `self: &mut Self`
    fn translate(&mut self, x: f64, y: f64) {
        self.p1.x += x;
        self.p2.x += x;

        self.p1.y += y;
        self.p2.y += y;
    }
}

// `Pair` owns resources: two heap allocated integers
struct Pair(Box<i32>, Box<i32>);

impl Pair {
    // This method "consumes" the resources of the caller object
    // `self` desugars to `self: Self`
    fn destroy(self) {
        // Destructure `self`
        let Pair(first, second) = self;

        println!("Destroying Pair({}, {})", first, second);
        // `first` and `second` go out of scope and get freed
    }
}

fn main() {
    let rectangle = Rectangle {
        // Associated functions are called using double colons
        p1: Point::origin(),
        p2: Point::new(3.0, 4.0),
    };

    // Methods are called using the dot operator
    // Note that the first argument `&self` is implicitly passed, i.e.
    // `rectangle.perimeter()` === `Rectangle::perimeter(&rectangle)`
    println!("Rectangle perimeter: {}", rectangle.perimeter());
    println!("Rectangle area: {}", rectangle.area());

    let mut square = Rectangle {
        p1: Point::origin(),
        p2: Point::new(2.0, 2.0),
    };

    // Error! `rectangle` is immutable, but this method requires a mutable
    // object
    //rectangle.translate(1.0, 0.0);
    // TODO ^ Try uncommenting this line

    // Okay! Mutable objects can call mutable methods
    square.translate(1.0, 1.0);
    println!("Square perimeter: {}", square.perimeter());
    println!("Square area: {}", square.area());


    //
    // separated from here
    //
    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();

    // Error! Previous `destroy` call "consumed" `pair`
    //pair.destroy();
    // TODO ^ Try uncommenting this line
}

P.S. 2024/6/1 self:インスタンス或はその参照とSelf:型について改めて

トレイトの戻り値の型Selfは、そのトレイトを実装する具体的な型を指し示し、一方selfはそのメソッドが定義された構造体または列挙型のインスタンス(self by value)または参照(self by reference)を指すので、Selfとは異なりメソッドの引数または関数呼び出しで利用されるキーワードです、実は両者の関係は以下の様になっています、

self:値渡し、self: Self の省略記法(コード中ではdesugarと記されています)

&self:不変参照渡し、self: &Self の省略記法

&mut self:可変参照渡し、self: &mut Self の省略記法

の関係になります

 

admin

 

 

std::iterの3種類の関数(@Rust)

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

のサンプルに出てくるイテレータですが、iter(コレクションの要素を借用)、into_iter(コレクションからのデータの取り出し)、iter_mut(コレクションの要素をミュータブルで借用)の3種類があります。

crateのドキュメント、

https://doc.rust-lang.org/std/iter/

に記載がある通りなのですが、exampleから該当部分のコードを抜き出してみると、以下のようになります。


~~iter~~
    for name in names.iter() {
        match name {
            &"Ferris" => println!("There is a rustacean among us!"),

~~into_iter~~
    for name in names.into_iter() {
        match name {
            "Ferris" => println!("There is a rustacean among us!"),

~~iter_mut~~
    for name in names.iter_mut() {
        *name = match name {
            &mut "Ferris" => "There is a rustacean among us!",

iterとiter_mutは”借用”なので元のコレクション(name)は再利用できますが、into_iterは”取り出し”なので元のコレクションは使えなくなります。

 

admin

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