夏に近づいたせいか、車内の温度は相当上昇するようで、土曜日にデモのため持ち出したホーバークラフト、今日取り出してみるとファンのホルダーがグダグダに変形しています。
PLAの耐熱温度は60℃ぐらいらしいから、車内だと今でも直射日光浴びる場所だとアウトの模様。この先意識しておかないと、
ABSだと耐熱性は問題なくとも、形状安定性特にファンのホルダーのようなそこそこ寸法精度が必要とされる場所には向いていないと思う。
admin
la vie libre
ようやくver.2を製作した、
改良点は、
① プロペラを水平(可変はできる)取り付けで横方向の推力が出ないようにした
② プロペラの風の抜けをよくできるような取り付け形状に改良
③ micro:bitを水平に取り付けてコンパス機能を使えるようにした
④ 金属ネジとか使わないで、かつコネクタも軽量化して、全体で二割ぐらいは軽量化
ver.1のようにファンが傾いていないから、割と安定してホバリングしている。
プロペラ駆動力(回転数)の調整でどこまで移動や回転が制御できるかはこれから、
<micro:bit制御用のコード>
・本体用
https://github.com/chateight/hober
ここでファンに与える電圧(回転数)を変えれば動きが制御できるはず
・コントローラー用
https://github.com/chateight/hober_ctl
<モーター駆動回路図>
admin
https://kudohamu.hatenablog.com/entry/2015/09/26/084621
で、以下のようなコードが出てきて、なぜhoge()()と()が二重になるのかなと思いましたが、
fn main(){
println!("{}", hoge()());
}
fn hoge() -> Box<dyn Fn() -> String> {
Box::new(|| -> String {
String::from("ほげー!")
})
}
Geminiで質問すると、
hoge()だけだと関数呼び出すだけで、hoge()()としないと戻り値であるクロージャーの実行はできないと以下のように言われました。
『まとめ:
hoge()()
は、hoge
関数を呼び出し、その結果として得られたクロージャを呼び出すという二つの操作をまとめて実行しています。』
「関数の戻り値としてのクロージャーを実行するなら二重括弧を使う」ということのようです
したがって、以下のように冗長に記述もできます。
let abc = hoge();
println!("{}", abc());
同じことは、クロージャーを戻り値にしている
https://isehara-3lv.sakura.ne.jp/blog/2024/04/05/クロージャーを戻り値にするrust/
のコードでも言えて、
let fn_plain = create_fn(); // return a closure
fn_plain();
と
create_fn()();
は等価です
admin
https://doc.rust-jp.rs/rust-by-example-ja/fn/closures/closure_examples/iter_any.html
と次のページに出てくるanyとfindですが、トレイトの型は以下のようになっていますが、findの&Self::Itemはクロージャが変数を参照として取ってくるので、クロージャーでの表現は二重参照の形になります。
<any/findのクレート表現>
fn any<F>(&mut self, f: F) -> bool
where
Self: Sized,
F: FnMut(Self::Item) -> bool,
fn find<P>(&mut self, predicate: P) -> Option<self::item>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool, // &Self::Item means closure variables are used as reference
以上の前提なので、
https://doc.rust-jp.rs/rust-by-example-ja/fn/closures/closure_examples/iter_find.html
からのソースコードでは&x -> &&x、x -> &xのように参照記号(&)が追加されています。
fn main() {
let vec1 = vec![1, 2, 3];
let vec2 = vec![4, 5, 6];
// `iter()` for vecs yields `&i32`.
let mut iter = vec1.iter();
// `into_iter()` for vecs yields `i32`.
let mut into_iter = vec2.into_iter();
// `iter()` for vecs yields `&i32`, and we want to reference one of its
// items, so we have to destructure `&&i32` to `i32`
println!("Find 2 in vec1: {:?}", iter .find(|&&x| x == 2));
// `into_iter()` for vecs yields `i32`, and we want to reference one of
// its items, so we have to destructure `&i32` to `i32`
println!("Find 2 in vec2: {:?}", into_iter.find(| &x| x == 2));
let array1 = [1, 2, 3];
let array2 = [4, 5, 6];
// `iter()` for arrays yields `&i32`
println!("Find 2 in array1: {:?}", array1.iter() .find(|&&x| x == 2));
// `into_iter()` for arrays yields `i32`
println!("Find 2 in array2: {:?}", array2.into_iter().find(|&x| x == 2));
}
admin
クロージャーを関数の戻り値にするときにも、Fn/FnMut/FnOnce指定が必要です。なぜならクロージャーの受け取りと同じくクロージャーの型は不明なので、
さらに関数の戻り値とするためにはクロージャーに渡される変数をmoveで参照では無く値渡しにしないといけません。以下の例でdataはクロージャーに渡しても戻り値では無い(参照が無効になることはない)ので、ここでのmoveはあっても無くても、値渡しだと時間が余計にかかるだけで、結果は同じですが、create_fn()中のクロージャーにはmoveがないとtextが参照では関数の戻りで参照無効となるのでコンパイルが通りません。
// return a closure
fn create_fn() -> impl Fn() {
let text = "Fn".to_owned();
move || println!("This is a: {}", text)
}
fn main() {
// return a closure
let data = vec![1, 2, 3];
// you don't need 'move' in this case becuase data is still available after this line
let closure = move || println!("captured {data:?} by value");
closure();
// call function and receive closure
let fn_plain = create_fn(); // return a closure
fn_plain();
admin
関数の引数としてクロージャーを渡せるのと同様に関数も引数として渡すことができます。
以下がサンプルのコードですが、ここではクロージャー(sqr)と関数(sqr_f)とそれらの引数も同時に関数(apply_clo())に渡しています。
当然トレイト境界と引数がクロージャーと同じ関数(ここではFn(i32))でないと渡せませんが、
fn apply_clo<F: Fn(i32)>(i: i32, f: F)
where F: Fn(i32),
{
f(i);
}
fn main() {
// ARG for the closure
let sqr = |y: i32| println!("{}", y*y);
// equivalent function
fn sqr_f(y: i32){
println!("{}", y*y);
}
apply_clo(23, sqr);
apply_clo(32, sqr_f);
}
admin
これもRustのメモリ管理のための特有機能になりますが、クロージャーを使う時にはその引数は、匿名構造体に保存されるようで、クロージャーを受け取るときにその引数がどういう使われ方をするかを指定するためにFn/FnMut/FnOnceの三種類のトレイトが存在します。
Fn/FnMut/FnOnceについての解説は以下のリンクが分かりやすい。
P.S. 2024/5/31
クロージャーはトレイトFn/FnMut/FnOnceのインスタンスです
https://qiita.com/hiratasa/items/c1735dc4c7c78b0b55e9
Rust by exampleの以下のリンクから、
https://doc.rust-jp.rs/rust-by-example-ja/fn/closures/input_parameters.html
コードを抜き出すと以下のようになりますが、ここでfn apply()とfn apply_to_3()はお互いに独立しています。
fn apply_to_3()はトレイト境界がシンプルで中で何らの変更もしていないのでFn指定になっています。
// A function which takes a closure as an argument and calls it.
// <f> denotes that F is a "Generic type parameter"
fn apply<f>(f: F) where
// The closure takes no input and returns nothing.
F: FnOnce() {
// ^ TODO: Try changing this to `Fn` or `FnMut`.
f();
}
// A function which takes a closure and returns an `i32`.
fn apply_to_3<f>(f: F) -> i32 where
// The closure takes an `i32` and returns an `i32`.
F: Fn(i32) -> i32 {
f(3)
}
fn main() {
use std::mem;
let greeting = "hello";
// A non-copy type.
// `to_owned` creates owned data from borrowed one
let mut farewell = "goodbye".to_owned();
// Capture 2 variables: `greeting` by reference and
// `farewell` by value.
let diary = || {
// `greeting` is by reference: requires `Fn`.
println!("I said {}.", greeting);
// Mutation forces `farewell` to be captured by
// mutable reference. Now requires `FnMut`.
farewell.push_str("!!!");
println!("Then I screamed {}.", farewell);
println!("Now I can sleep. zzzzz");
// Manually calling drop forces `farewell` to
// be captured by value. Now requires `FnOnce`.
mem::drop(farewell);
};
// Call the function which applies the closure.
apply(diary);
// `double` satisfies `apply_to_3`'s trait bound
let double = |x| 2 * x;
println!("3 doubled: {}", apply_to_3(double));
}
Fn/FnMut/FnOnceの三種類のトレイトは、それぞれ以下のようになっていてFnMutはFnOnceをFnはFnMutをそれぞれ継承しています。それぞれの関数の引数を見ると、引数をどのように扱っているかが分かりますが一番過激なのがFnOnce、ただしdropしてしまうので一度しか使えない、変更だけならFnMut、参照するだけならFnというふうになります。
上記のコードで
pub trait FnOnce
where
Args: Tuple,
{
type Output;
// Required method
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
pub trait FnMut: FnOnce
where
Args: Tuple,
{
// Required method
extern "rust-call" fn call_mut(
&mut self,
args: Args
) -> Self::Output;
}
pub trait Fn: FnMut
where
Args: Tuple,
{
// Required method
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
admin
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
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
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