所有権と借用について(@Rust)

Rustのメモリ管理の特徴の最大の機能と言えるものが所有権ですが、所有権(以下ではほぼ借用についての記述)と参照借用の特徴的なところを簡単なコードで説明できるようにしてみました。まあ、オリジナルのドキュメント読めばわかることですが。

以下のコメントでcase1~4がそれに該当するところです。

case1 : mutableな変数(ここではString型)をmutableで参照借用すると、元の変数は変更ができなくなるし、一度借用したらその後の複数借用もできない。変更を伴うと制限が出てくるのは、所有権に類似してます。

case2 : mutableにできる変数をimmutableで扱う場合は変更される可能性がないので、参照処理はcopyになり尚且つ複数のcopyも許容されます。

case3 : mutableにできない静的領域に格納される変数の場合には参照(&)を付加しなくとも暗黙で参照(copy)できます。文字型(char)はcopy traitを実装しているから。(ヒープを利用するString型のcopyにはclone()を使います)

case4 : 参照と非参照の比較はできないので、参照戻し処理(*の付加)が必要になります。case1でも参照型で使える関数の制限で参照戻しを使っていますが、

fn main() {
    // case1 : borrow in "String":mutable case
    //
    let mut aa = String::from("abc");       // variable length "String"
    let bb = &mut aa;
    bb.push_str("gh");
    let cc = format!("{}{}", "ko", bb);    // Linking "Strings"
    println!("mutable case (bb, cc) : {}, {}", bb, cc);

    //aa += "refa";     // error ; second mutable borrow occurs here, after first borrow you can't change the original content
    *bb += "refb";      // you can't use `+=` on type `&mut String`, use reference return
    println!("updated bb : {}", bb);

    // case2 : immutable case
    //
    let aa_i = String::from("kile");
    let bb_i1 = &aa_i;
    let bb_i2 = &aa_i;
    println!("immutable case (bb_i1, bb_i2) : {}, {}", bb_i1, bb_i2);

    // case3 :  literal(immutable) case in "str"
    //
    let aa_c = "abc";
    let bb_c = aa_c;    // refrence in immutable case, you can eliminate "&"
    //bb_c.push_str("gh");  // "push_str" is not found in `&&str` since bb_c is immutable
    let cc_c = format!("{}{}", "ko", bb_c); // linked output is a "String"
    println!("bb_c, cc_c : {}, {}", bb_c, cc_c);

    // case4 : reference return
    //
    let original = String::from("def");
    let reference = &original;
    if original == *reference {        // comparing "String == &String" causes compile error, if "*" is not used
        println!("equal");
    } else {
        println!("not equal");
    }
}

所有権の本質は、ある変数(ヒープ上の変数、静的領域上の変数に対しては所有権の概念は無い)を変更できるのは所有権を持っている唯一の変数だけだよといっていますが、借用は所有権は移動せずに参照/変更する権利は有すると言うことになります。変更できる借用(可変借用)は実質的には所有権を移動することと同等なので、掛かる制限が出てくると言うことになります。

 

admin

 

Maker Faire Tokyo 2023

本日初めて行ってきました。オレイリージャパンの主催でスポンサーも多数、出展は個人レベルから趣味のグループ、大学が主体でメーカーは少ない印象です。

そのうちのいくつかの作品から、全部の写真は多すぎなのでおいおい整理、

1 静電容量方式でキータッチすると音階を指定できるキーボード。

2 自作のMRI、液体窒素冷却とかしなくとも解像度が低くなるけれども核磁気共鳴はセンスできるそうです。画像に落とし込むソフトも全部自作だそうです。おそらく標準のライブラリはあるでしょうが。

3 両手で持って、リングのように見えるのが弦相当で演奏できる電子楽器。

会場の作品を見ると、多くはラズパイ、M5Stackを使っています。これはM5Stackのブース。

全部を細かく見だすと、到底一日ではカバーできそうもないので最後は結構駆け足になってしまいました。

個人的に会場の作品制作などを見て、あれば良さそう(欲しい)と思ったのは、レーザーカッターと多軸関節ロボットアーム。どちらも10万円以下で個人でなら使えそうなものが手にはいる。

 

admin

 

 

 

 

クロージャー(Golang and Rust)

現代の言語ではクロージャー機能を多くの言語で持っていますが、同じ機能(単純な1の加算)をGolangとRustで実装の比較。Rustの説明で出てくる、クロージャーは環境をキャプチャーできる匿名関数という定義はわかりやすい。

<Golang>

package main

import "fmt"

func add(i int) func() int {
	n := i

	clo := func() int {
		n++
		return n
	}

	return clo		// equivalent to specify anonymous function here and maybe it's more popular
}

func main() {
	a := add(1)
	for i := 1; i < 10; i++ {
		fmt.Println(a())
	}
}

<Rust>

fn f1(i: i32) -> Box<dyn FnMut -> i32> {	// FnMut recieves &mut self
	let mut i = i;						// dyn keyword sepcifies a trait pointer in the heap area
	Box::new(move || {				// force to allocate values in the heap area
		i += 1;
		i
	})
 }
 
 fn main() {
	 let mut cup = f1(0);
	 for _ in 1..10 {
		 println!("{}", cup());
	 }
 }

コードの参考は、

https://scrapbox.io/takker/Rustで関数を返す関数を作

FnMutの解説は、

https://qiita.com/hiratasa/items/c1735dc4c7c78b0b55e9

Fnでは変更できないし、FnOnceでは一度しか呼べないのでFnMutの指定になります。

比較してみると、Rustの方が細かな指定が必要ですが、これはメモリ管理に関する指定を明示的に行わなければいけない言語だからでしょう。したがってこれぐらいの例では変わらないけれども、コードは長めになります。比較してGolangは細かな操作はしなくとも使うだけなら簡単ということになるでしょうか。

Box<dyn … >については、

Boxは変数をスタック領域ではなくヒープ領域への割り当て、dynについては以下の通り、

https://doc.rust-lang.org/stable/rust-by-example/trait/dyn.html

“Rust tries to be as explicit as possible whenever it allocates memory on the heap. So if your function returns a pointer-to-trait-on-heap in this way, you need to write the return type with the dynkeyword

 

admin

 

Rustで特徴的と思ったところ(その1)

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

型定義しない気持ち悪さ(@TypeScript)

をTSとTSからtscで生成されるJSを比較してみます。

以下はTSのコード、

// safety
type WeekDay = 'Mon' | 'Tue' | 'Wed' | 'Thu' | 'Fri'
type Day = WeekDay | 'Sat' | 'Sun'

function getNextDay(w: Day): Day | undefined{
    switch (w){
        case 'Mon': return 'Tue'
        case 'Thu': return 'Wed'
        case 'Wed': return 'Thu'
        case 'Thu': return 'Fri'
        case 'Fri': return 'Sat'
        case 'Sat': return 'Sun'
        case 'Sun': return "Mon"
    }
    return undefined
}

console.log(getNextDay('Mon'))

tscでコンパイルされて生成されるコード、

function getNextDay(w) {
    switch (w) {
        case 'Mon': return 'Tue';
        case 'Thu': return 'Wed';
        case 'Wed': return 'Thu';
        case 'Thu': return 'Fri';
        case 'Fri': return 'Sat';
        case 'Sat': return 'Sun';
        case 'Sun': return "Mon";
    }
    return undefined;
}
console.log(getNextDay('Mon'));

もちろんどちらも結果は同じですが、素のJSでは裸で外を歩いているように感じます。TSの場合には最初に取り得る型を定義することでその型以外を指定すればコンパイラ(VScode)がチェックしてくれる(例えばgetNextDay(w: Day)のDayをWeekDayにすればcase 'Sat'とcase 'Sun'はエラー表示表示されます)訳だから、数百行程度のプロジェクトでもTypeScriptを使うメリットはあると思います。

 

admin

micro:bitのLED表示時間が異常に長い件について

直前のブログでLED表示時間が異様に長い件、micro:bitのドキュメントにその理由と思われる記載がありました。

https://lancaster-university.github.io/microbit-docs/ubit/display/?fbclid=IwAR0ZlyEd0pQnAIEmQUUK_gUnD-jalUa-hzdmIHjCRyauOcIJwdLBerLbFyI

overviewの最後にある通り、

“In it’s normal mode, the display will update every 18ms (55 Hz). If the display is in light saving mode the period is changed to 15ms (66 Hz).”

18ms毎にupdateされるようなので、この時間がLED表示データ書き込み時間として見えて来ているようです。マルチタスク動作ではないだろうmicrobitのファームウェアでは。

 

admin

Node.jsフレームワーク(Express-Generator)でのページ遷移

ラズパイにはExpress-Generatorをインストールしていましたが、MacBookにもインストールして久しぶりに触っています。Express-Generatorはwebアプリ雛形作成のためのツールの一つです。webアプリ作成のためには理解すべき点がいくつかありますが、動的なページを作成するためのデータの与え方はその一つです。

以下は関連するディレクトリを表示していますが、index.jsでviews配下のindex.pugのコンテンツを作るようになっています。

index.jsソースの一部(dbName())は記載していませんが、データベースからの読み出しを行なっています。本タイトルと直接の関係はないので省略。

var express = require('express');
var router = express.Router();

var nameList = "";

/* GET home page. */
router.get('/', function(req, res, next) {
  var response = Math.floor(Math.random() * (100 - 1)) + 1;
  
  dbName();

  const wait = () => {
  res.render('index', { title: 'Express', data: response, db: nameList});
  }
  setTimeout(wait, 3);
});

res.render()の第二引数以下がindex.pugに渡されてhtmlのコンテンツを構成しています。雛形ではtitle一個しかありませんが、カンマ区切りで任意の個数を追加できます。ここでは1~100までの範囲の乱数をdataとして、データベースから読み出したデータを変数名dbでindex.pugに渡しています。

index.pug

extends layout

block content
  h1= title
  p Welcome to #{title}

  p #{data} 

  p #{db}

SQLite3のデータベースアクセスも非同期で実行されるので、ページ作成が先行して実行されてdbデータの供給が間に合わないので、仮に時間待ち3msを入れていますが、あくまでデバッグ専用でいずれ修正の予定。

 

admin

 

 

ioutilもdeprecated(Golang)

タイトルの通りですが、1.20以降ではそうなります。実は1.16でそういう風に宣言されていたらしい。以下のリンクを参照、

bytes, err := ioutil.ReadFile("sample.json")

bytes, err := os.ReadFile("sample.json")

おそらくファイル全体を読み込むのは、メモリ効率が良くないし、Goの美学とも相入れないのでos.ReadFileを使えということなんだろうと思います。

https://future-architect.github.io/articles/20210210/

 

admin

MacBook Airのゴミ箱がワンクリックで消せない

まあMacOSではありがちな現象ではありますが、ゴミ箱がワンクリックで消せなくて、わざわざゴミ箱の中に入ってファイルを全選択して消去。

週一のリフレッシュブートで回復しているから、何らかのOS問題。回避が簡単な問題なら最近気にならなくなった。

 

admin

依存性注入(Golang)

依存性注入(DI : Dependency Injection)は他の言語でもありますが、Goの場合にはより構造が単純化されると思います。

以下のコードは、

https://qiita.com/lostfind/items/cae2bca46d903bea167c

からですが、DIを使わないと電球の種類が変わる都度、部屋の工事が必要になるのですが、DI使って部屋にはソケットだけ用意して電球の種類はmain()ルーチンで簡単に変えられるようにしています。DIのメリットは変更発生時の変更範囲が分離されることと、テストが容易(関連するモジュールがなくてもできる)あたりがメリットになるでしょう。プログラムのライフサイクルで保守が大きな比重を占める訳なので、変更に強いコードと言えます。反面コードはその分冗長になります。

package main

import (
	"fmt"
)

func main() {
    lightOne := new(Incandescent) 	// only change these lines if new lighting is introduced
    lightTwo := new(LedLight)		//

    myRoom := NewRoom(lightOne, lightTwo) // DI or object Injection

    myRoom.SwitchOnOne()
    myRoom.SwitchOnTwo()
}

type LightSocket interface {
    LightUp() string
}

// room has two sokets
type Room struct {
    LightOne LightSocket		// prepare only socket, not bulb
    LightTwo LightSocket
}

// define switch on method of the two sockets
func (r *Room) SwitchOnOne() {
    fmt.Println("1番照明:", r.LightOne.LightUp())
}
func (r *Room) SwitchOnTwo() {
    fmt.Println("2番照明:", r.LightTwo.LightUp())
}

// Constructor Injection
func NewRoom(lightOne, lightTwo LightSocket) *Room {
    room := &Room{
        LightOne: lightOne,
        LightTwo: lightTwo,
    }
    return room
}

// Led light
type LedLight struct{}

func (*LedLight) LightUp() string {
    return "LEDが光るよ!"
}

// Filament bulb
type Incandescent struct{}

func (*Incandescent) LightUp() string {
    return "フィラメントが光るよ!"
}

DIはデザインパターンそのものです。

 

admin