本居宣長の言う大和魂というのは、維新の志士そして旧日本軍の精神につながっていると思いますが、宣長の言う大和魂は決してナショナリズムではなくナショナリティのことを言っているだけだろうと思う。したがってそれを都合よくナショナリズムに解釈するのは間違っている。漢意(からごころ)は本来の日本人の精神とは違うから大和魂を大切にするのは、宣長が決して儒教を知らなかった訳ではないから、守破離の結果として大和魂に行き着いたという風に解釈すべきだろう。
admin
la vie libre
Rustのオンラインブック、
https://doc.rust-jp.rs/book-ja/title-page.html
を読み始めて、第5章までの分です。自分の他言語経験から見てユニークと思えるところを、並びは時系列です。特にC/C++などで起こるメモリ管理上のバグの作り込みを防ぐためのメモリ管理機能(所有権)がいちばん特徴的だろうと思う。
・crate : クレートはRustソースコードを集めたものである、バイナリ形式でもそういうけども
・Cargo.toml : Tom’s Obvious, Minimal Language、パッケージのリストと版数を指定するテキストファイル
・Cargo : Rustのビルドシステム兼パッケージマネージャ
cargo checkでコンパイルエラーがチェックできる
・println! : !はマクロの意味、簡易に結果出力で使用で構造体ではコンパイルエラー、回避方法(20行ぐらい下)はありますが
・関連関数
String::new() :newは関連関数で、Stringインスタンス作成する
・参照変数のmutable化
io::stdin().read_line(&mut guess) : &mutは参照変数をミュータブルにする、記法はmut &guessではない
・Cargo.lockファイル : ビルドの再現性確保のためにクレートのバージョンを保存しておく、自動生成されユーザがいじるファイルでは無い
・traitはデータ型を分類する仕組み、crateの要素(任意の型となりうるSelfに対して定義されたメソッドの集合のこと)、類型的にはJavaのinterfaceのようなもの
・Shadowing : 前の値を新しい値で覆い隠す(shadowする)ことが許されている、型は違っていても同じでも良い
・タプルの要素は型が違っても大丈夫
let x: (i32, f64, u8) = (500, 6.4, 1);
let five_hundred = x.0; // タプル要素へのダイレクトアクセス
・Rustの配列は固定長、ベクター型は可変長
let a: [i32: 5] = [1, 2, 3, 4, 5];
・戻り値の指定方法は;をつけてはいけない、-> は戻り値の型を指定
fn five() -> i32 {
5 // it’s formula not statement
} // return value
・条件式を右辺に記述できる
let number = if condition { 5 } else { 6 }; // possible if both type is same
・所有権:これはRustのコア機能(メモリ管理がRustの一大機能)、本質はヒープ領域の管理になりますが
・println!に指示する: 直接エンドユーザ向けの出力で、構造体はこれではダメで
#[derive(Debug)]行を追加必要
・メソッド記法は構造体の文脈で定義(impl Rectangle)される、Golangの構造体との関連付けに書式は違うが似てると思う
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 { // implしてるから&self、構造体インスタンスへの参照
self.width * self.height
}
}
・関連関数:implブロック内で定義される、selfを引数に取らない関数。構造体と関連づけられていないからメソッドではない、String::new()はその例。よくある使い方は構造体のインスタンスを返却する関数。
admin
本命だろうと思うDockerでやってみる。以前に、
https://isehara-3lv.sakura.ne.jp/blog/2023/04/22/dockerでgolangのbuild環境を作る/
で作成しているDockerのコンテナ起動して、コンソールからRustインストールすると当たり前にコンパイルできる。crossを使わなくてcargoで普通に管理できるからやはりこれが本命。
ペリフェラルを使うためのライブラリは、
https://github.com/golemparts/rppal
を使うのが一般的のようなのでこれを使ってみます。基本のLチカというサンプルがあったので、GPIOを使ったサンプルプログラムをビルドしてみました。
https://misoji-engineer.com/archives/rust-led.html
このソースのままでmain.rsにコピーしてcargo buildでコンパイルが完了しました。
コンパイル前には、Cargo.tomlの[dependencies]にrppalの追加が必要です。Rustは必要なライブラリをソースコードとは別に定義ファイルで管理するようになっています。
# cat Cargo.toml
[package]
name = "led_blink"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rppal = "0.14.0"
初回はrppalのコンパイルも入るので多少時間はかかりますが、次回からは短縮されるはずです。
# cargo build
Updating crates.io index
Downloaded rppal v0.14.1
Downloaded libc v0.2.147
Downloaded 2 crates (766.8 KB) in 0.86s
Compiling libc v0.2.147
Compiling rppal v0.14.1
Compiling led_blink v0.1.0 (/root/rust/led_blink)
Finished dev [unoptimized + debuginfo] target(s) in 21.72s
P.S. (2023/8/5)
ラズパイzeroに転送して実行させると、
$ ./led_blink
Illegal instruction
と言われた、ラズパイzero上にRustをインストールしてビルドさせるとおよそ2分でビルド出来たから、実機ビルドでも取り敢えず許容範囲。
<実行させたコード:0.1秒ごとにハイ・ローを切り替え>
extern crate rppal;
use std::error::Error;
use std::thread;
use std::time::Duration;
use rppal::gpio::Gpio;
const GPIO_LED1: u8 = 17;
const GPIO_LED2: u8 = 27;
fn main() -> Result<(), Box> {
let mut led1 = Gpio::new()?.get(GPIO_LED1)?.into_output();
let mut led2 = Gpio::new()?.get(GPIO_LED2)?.into_output();
// Blink the LED by setting the pin's logic level high for 1000 ms.
loop{
led2.set_high();
led1.set_high();
thread::sleep(Duration::from_millis(100));
led1.set_low();
led2.set_low();
thread::sleep(Duration::from_millis(100));
}
}
確認はピンの信号波形をオシロで観察、
admin
以下のサイトを参考にx86のLinux環境でのクロスはできた。
https://betterprogramming.pub/cross-compiling-rust-from-mac-to-linux-7fad5a454ab1
結構普通のやり方だと思うけど、brewでターゲット用のlinkerをインストールしているのが大事なところでしょう。ラズパイ用がbuild出来ないのもおそらくlinkerをインストールしていないからでしょう
% brew install SergioBenitez/osxct/x86_64-unknown-linux-gn
.cargo/config.toml を作成編集
and adding the linker for the target:
[target.x86_64-unknown-linux-gnu]
linker = "x86_64-unknown-linux-gnu-gcc"
% TARGET_CC=x86_64-unknown-linux-gnu cargo build --release --target x86_64-unknown-linux-gnu
Compiling rust v0.1.0 (/Users/xxxxx/rust)
error[E0463]: can't find crate for `std`
=> 見覚えのあるエラーがやはりでる。
% rustup target add x86_64-unknown-linux-gnu
でライブラリインストールして解決。
% TARGET_CC=x86_64-unknown-linux-gnu cargo build --release --target x86_64-unknown-linux-gnu
Compiling rust v0.1.0 (/Users/usamiryuuichi/rust)
Finished release [optimized] target(s) in 1.60s
.cargo/config.tomlはディレクトリの親含めて検索するようですが、今回はプロジェクトのルートに作成。
クロスコンパイルなのでコンパイル時間はネーティブよりかかるのはGolangと同じです。Docker使ってもできるはず、というかラズパイ用のlinkerは同サイトには見えないのでDocker使うのが一番素直な感じがします。Golangでネーティブのgccを使わない限りにおいてはDockerは必要ないので、この点ではGolangのほうが使いやすさはあります。
動作はIntel MacのVMware上のUbuntuで確認しました。
admin
動かすのはラズパイでIoT的な物にしたいが、まずはMacで開始します。
Rust関連のインストール(やり方は公式ページなど参照)、
% rustc --version
rustc 1.71.0 (8ede3aae2 2023-07-12)
% cargo version
cargo 1.71.0 (cfd3bbd8f 2023-06-08)
% rustup --version // Rust tool chain, cargo(Rust's package manager)とは併用
rustup 1.26.0 (5af9b9484 2023-04-05)
cargo-editはcargoの拡張機能、単独のコマンドではない
% cargo install cargo-edit
% cargo install cross
クロス環境用にcrossをインストールしますが。本来的にはcargoはRustのパッケージ管理とビルドツール。crossはクロスコンパイル環境ですが、実はcrossはDockerにターゲットDockerイメージを展開してコンパイルするようになっています。
Intel Mac用のコンパイル(cargo build)と実行(cargo run)
コードは、
https://isehara-3lv.sakura.ne.jp/blog/2023/01/19/rustの基本的なsyntax/
% cargo run --target x86_64-apple-darwin
Finished dev [unoptimized + debuginfo] target(s) in 0.00s
Running `target/x86_64-apple-darwin/debug/rust`
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10
内部的にはRosetta2使っているだろうから、Intel用のバイナリでもそのまま実行できます。もちろん実行ファイルを直接呼び出して
% ./target/x86_64-apple-darwin/debug/rust
も結果は同じ。Intel Macに転送して実行してもきちんと実行できました。
P.S. ラズパイ用のクロスコンパイルはエラーになる、追加の設定(Linker設定してないから)が要りそう。ネットの情報は古くてあまり参考になるものは少ない。
% cargo build --target thumbv6m-none-eabi
Compiling rust v0.1.0 (/Users/usamiryuuichi/rust)
error[E0463]: can't find crate for `std`
~~以下省略~~
admin
を今年の後半はRustの勉強兼ねて使ってみようと思う。GPIOなどの固有ハードウェア操作用の基本的なライブラリはすでに存在するだろうから。
https://misoji-engineer.com/archives/rust-led.html
クロス開発環境はDocker(GolangのネーティブC環境の必要性と同じく)になるのかそれともGolangと同じようにターゲット指定で済むのか、その前にRustの基本的な部分の習得が先ですが。
https://isehara-3lv.sakura.ne.jp/blog/category/rust/
はPlayground使って初めてのRustですが、オンラインの学習用には、
https://doc.rust-jp.rs/book-ja/title-page.html
あたりが適切のように思う。
P.S. (2023/8/2)
クロスコンパイルはcrossツールを使いますが、実はDockerの中にターゲットのイメージを展開して実行されます。従って賢いやり方ですね、Golangと比べても。
admin
先日のサンプルを動かしていて気づいたこと、
%npm startでサーバー起動してブラウザの開発者ツール(Chrome)で見ているとサーバー停止後に以下のようなメッセージが出てきます。
public/srcディレクトリに該当しそうなソースは無いからnode_modulesの中?しかしライブラリが勝手に通信はしないだろうから今のところはアンノーンな出来事です。
admin
propsとstateというのはReactで重要な役割を果たします。props(properties)は親のコンポーネント(ここでは一つの関数がコンポーネントに相当、常に大文字で定義されます)から子のコンポーネントに値(値の型はなんでも受け入れそうなので型定義する仕掛けが必要でしょう)を渡し、stateはReact内での状態保持のための仕組みです。
以下非常に単純なbuttonをクリックするとカウントアップする仕組みをpropsとstateを使って作ってみたものです。
ただし、button className="square"に対応するCSSは定義していません。
<App.js>
import { useState } from "react";
function Value() {
let [value, setValue] = useState(0);
function handleClick() {
value += 1;
setValue(value);
}
return (
<button className="square" onClick={handleClick}>
{value}
</button>
);
}
function Message({ mes }) {
return <p>{mes}</p>;
}
export default function Count() {
return (
<>
<Message mes="Hello counter" />
<Value />
</>
); // mes is a 'props'
}
% rpm startでブラウザ起動され、ボタンをクリックすると数字がカウントアップされます。
おそらくReactでインタラクティブに動作する最もシンプルなサンプルだろうと思います。
もう少し複雑になるとtutorialの三目並べですが、
https://ja.react.dev/learn/tutorial-tic-tac-toe
ここでも機能として使っているのはpropsとstateですが、JavaScriptは関数も引数で渡せるので、それを多用しています。
また、handleClick():関数、onClick:プロパティの命名則はhandleXxx/onYyyのようにhandleとonで始めるのだそうです。
admin
フロントエンドではReactを使うのが標準になっているようで、特に最近流行のSPAなどとの相性が良いらしい。
Reactが優れている点はいくつかあるようですが、個人的には仮想DOMを使うことでページの更新が速やかにできる(レンダリングコストの低減)はメリットだと思う。
Reactを学ぶサイトにはいくつかありますが、標準的なところでは、
あるいは、
https://learn.microsoft.com/ja-jp/windows/dev-environment/javascript/react-beginners-tutorial
あたりが良さそうです。いずれにしても全体構造をさっと解説してあるようなサイトはなさそうで、ステップバイステップか。
ReactはJavaScriptのライブラリに過ぎないのですが、裏の仕組みとしてはNode.jsが主要な役割を果たしているようです。
% npx create-react-app some_app_name
で作成されるディレクトリ構造を見るとNode.jsに似ている(そっくり)ように思うし、
% npm start
でWebサーバーを起動するのも同じじゃないかと思う。Webサーバーを起動しているからサーバーサイドとクライアント間の通信もできるはず。
プロダクションビルドは、
% npm start
ではなく、
% npm run build
を使えと言われて、このコマンドを実行すると新たにbuildディレクトが作成されました。(以下の図(hello_reactディレクト)はVScodeから見えるbuildディレクトリ存在前のディレクトリ構造)中身を見ると、そのままサーバーに配置すれば使えるようになっているようだし、npm run buildの実行時のメッセージには以下のような出力がされるので、serveをインストールして起動するとnpm startと同様なページが表示されます。
The build folder is ready to be deployed.
You may serve it with a static server:
npm install -g serve
serve -s build
Reactの環境を作るのはコマンド一発で作成されますが、そこから作成されるファイル構造は上の図のようになっています。
webサーバー起動して表示される画面はこんな画面。
react.devの最初のtutorial(三目並べ)をbuildするのもNode.jsで変換されるんだろうと思いますが、以下のreact.devのtutorialのサンドボックスから見えるディレクトリ構造は、
/public/index.html、App.js/index.jsという同じ作りになっているから、この構造がスタートポイントと思えば良さそうです。index.html -> index.js -> App.jsと呼び出しているようです。
左上のメニューを選択して、File -> Export to ZIPでFilesメニューに見えるプロダクションビルドがZIPファイルでダウンロードできます。
admin
それゆえにpromiseとか、async/awaitとかの非同期処理のための機能が用意されているのですが、
① ブラウザならばWeb Worker:一部制限はあるけれどもマルチスレッド動作ができる。こういう機能無かったらブラウザでのマルチスレッド処理は著しく不便になりそう、元々ブラウザは同時にたくさんのスレッドが動いているし、
スレッド間通信(postMessage/onmessage API)はevent emitterのemit/onと類似だし、Golangのチャネルとも似ていますが、安全に通信(スレッド間)を行おうとするとこのようなAPIが必要になるのはどの言語でも共通でしょう。
② Node.jsならば子プロセス、マルチスレッドのためにはworker_threadというAPIが用意されているようです。子プロセスなのでスレッドよりもリソースの分離性は良くなるでしょう、負荷は高くなりそうですが。
プロセス間通信はsend/on APIを使うのはWeb Workerとも類似だし、子プロセスの起動にforkを使うのもほぼそうだろうと思います。
個人的にはNode.jsではマルチスレッド(プロセス)を使ってみる機会がありそうです。
admin