struct{}は型(type)を表現しているし、struct{}{}はstruct{}のインスタンス、従って変数の宣言時には型表現としてのstruct{}を使い、変数への代入時には値(インスタンス)としてのstruct{}{}を使わないといけません。
var empt struct{}
empv := struct{}{}
考えてみればそうですが、混乱しやすいかもしれない
admin
la vie libre
struct{}は型(type)を表現しているし、struct{}{}はstruct{}のインスタンス、従って変数の宣言時には型表現としてのstruct{}を使い、変数への代入時には値(インスタンス)としてのstruct{}{}を使わないといけません。
var empt struct{}
empv := struct{}{}
考えてみればそうですが、混乱しやすいかもしれない
admin
Goでの特徴的な機能の一つであるgoルーチンですが、その終了判定あるいはチャネルの選択時の一つのパターンがdoneパターンと言われるもの。
コードのベースは以下からですが、
https://github.com/mushahiroyuki/lgo/blob/main/example/ch10/ex1009.go
実はチャネルサイズが10なので、以下のgoルーチンのループでは11以降はチャネルへの書き込みができないので待ちになります。実質はmainルーチンが終了するとgoルーチンも終了されるので処理上の問題はないのですが、
ここでgoルーチン側で終了待ちをするためのdoneパターンを導入してみます。
close(done)がgoルーチンへの終了シグナルになりますが、goルーチン側ではselect/caseを使っています。チャネルの処理が継続できる条件が複数あるときに、継続可能となった処理をselect/caseで選択して実行するものです。select/case文の特徴的なところは、複数の条件が成立しているときにはランダムで継続可能処理を選ぶことでswitch文のように上から順番のような優先順位はつけないということです。
func main() {
ch := make(chan int)
var result []int
done := make(chan struct{})
go func() { // 処理してもらう数値をchに入れる
for i := 0; i < 100; i++ {
select {
case <- done:
fmt.Print(". ")
return
case ch <- i:
}
}
}()
result = processChannel(ch)
close(done)
time.Sleep(1000)
fmt.Printf("result: %d\n", result)
}
このサンプルでは確実にdone処理を実行するためにmainルーチンで1000nsの待ち時間を入れています。
実行すると、例えば以下のようになります。
ゴルーチン 起動完了
process: 0 0 0
process: 9 81 0
process: 5 25 2
process: 6 36 2
process: 4 16 0
process: 7 49 1
process: 1 1 2
process: 8 64 2
process: 2 4 1
process: 3 9 1
. result: [0 81 16 9 4 49 64 25 1 36]
admin
という情報を見たので、ダウンロードして立ち上げてみて、最初の二回は反応なくなったけど、3度目からは立ち上がるようになった。Intel版でも割と起きる現象だから、Apple silicon限定というわけでもない。
ただしFinderのアプリケーションからは見えず、ユーザディレクトリのApplications配下で見えるからDockに配置。
作成したパーツはクラウドに保存されているから、インポートとかは不要。
アプリ情報見てみるとrosetta2モードで動作しています、ネーティブ対応は今年の夏頃と言っていますから。
Intel Mac必須だった障壁また一つ乗り越えたから、そろそろApple silicon統一でも環境としては問題ないかもしれない。新規プラットホーム投入でも、二年半経過すると概ねそんな感じになるんだね。
P.S. 2023/3/14
アプリ立ち上げ時間比較(Dockのアイコンクリックから立ち上がり画面までストップウォッチ計測)
・2029 Intel i7 16GB 一回目:60秒、二回目:40秒
・M1 MacBook Air 16GB 一回目:33秒、二回目:36秒
ほぼ同じぐらいかと思っていたけど、M1の方がRosetta2にも関わらず高速立ち上がりだからApple siliconって優秀。
admin
依存性注入(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
今更ですが、fmtパッケージにはStringerインターフェースが定義されているので、StringerインターフェースのメソッドString()を独自に実装すると、実装したメソッドが有効となるのでその書式でPrintされます。
以下はGlangのAPIからのコードですが、String()を実装すればその書式になるし、未実装ならば構造体のままでプリントされています。
package main
import (
"fmt"
)
// Animal has a Name and an Age to represent an animal.
type Animal struct {
Name string
Age uint
}
// String makes Animal satisfy the Stringer interface.
func (a Animal) String() string {
return fmt.Sprintf("%v (%d)", a.Name, a.Age)
}
func main() {
a := Animal{
Name: "Gopher",
Age: 2,
}
fmt.Println(a)
}
<String() string実装>
Gopher (2)
<デフォルト>
{Gopher 2}
多少事情は異なりますがtime.Timeでは、time.Timeが独自のString()メソッドを実装しているから意図した通りにはならず独自のStringメソッドが補完してくれるようです。
https://tutuz-tech.hatenablog.com/entry/2019/11/28/091036
admin
3Dプリンタのフィラメントは吸湿しやすく、特に夏場の高湿時には過酷です。吸湿すると造形品質劣化するのと、ノズルも痛むし、硬化して折れてしまって送りもうまくいかなくなります。
一度吸湿したフィラメントを乾燥できるというものがあったので購入してみました。
https://www.amazon.co.jp/gp/product/B08C9RF7R7/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1
熱中症指数把握のためのM5Stackセンサーが温湿度測定にピッタリなのでモニターしてみました。
湿度は今少し下げたほうがいいだろうから、中に吸湿剤も入れたほうが良さそうです。効果が明確にわかるのは夏場になるだろうから、それまでに環境を整備していきます。
admin
これを使って、USBシリアル経由でProcessingでカード情報を受け取り、UIDと参加者の対応表からカードをタッチした参加者は出席とSQLiteのテーブルに書き込み、デスクトップ画面に表示をするようなアプリです。
M5Stickc plusとProcessingのコードは以下のリンクから、
https://github.com/chateight/rfid
注意点はserialEvent()は割り込み処理なので、この中で共通リソースを変更すると、他で使用中のコードからは意図しない(不規則な)変更に見えるので、この中では共通リソースの書き込み処理を行ってはいけない。具体的にはdbTableUpdate()の呼び出しをserialEvent()中で行っていたら、draw()からの呼び出し中にString[] membersの配列を破壊してパニックが発生しました。dbTableUpdate()の実行中に配列を書き換えなければ問題ないのでそれで対応。
10人分の登録をしたらこんな画面になります。
admin
https://isehara-3lv.sakura.ne.jp/blog/2023/02/17/mifareカードリーダー/
M5StackでRFカードリーダーのアプリ作ろうと思っていましたが、カードリーダー専用ならばM5Stackである必要性はないので、より小型のM5Stickc plusを使ってみました。
サイズの差、
動かしてみたところ、
M5StackとM5Stickc plusにはいくつか差分がありますが、以下はM5Stickc plus用のコードです。
主な違いを列挙すると、
5. 電源オンオフは、「M5」と書かれたボタンを正面に見て左側にあるボタンを6秒長押しすると電源が切れます。電源ONは同じボタンを押します。
/*
to change for the M5stickc-plus 2023/2/23
*******************************************************************************
* Copyright (c) 2022 by M5Stack
* Equipped with M5Core sample source code
* 配套 M5Core 示例源代码
* Visit for more information: https://docs.m5stack.com/en/core/gray
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/gray
*
* Describe: RFID.
* Date: 2021/8/19
*******************************************************************************
Please connect to Port A(22、21),Use the RFID Unit to read the Fudan card ID
and display the ID on the screen. 请连接端口A(22、21),使用RFID Unit
读取ID卡并在屏幕上显示。
*/
#include <m5stickcplus.h>
#include "MFRC522_I2C.h"
MFRC522 mfrc522(0x28); // Create MFRC522 instance. 创建MFRC522实例
void setup() {
M5.begin(); // Init M5Stack. 初始化M5Stack
//M5.Power.begin(); // Init power 初始化电源模块
M5.Lcd.setRotation(3);
M5.lcd.setTextSize(2); // Set the text size to 2. 设置文字大小为2
M5.Lcd.println("MFRC522 RFC reader");
Wire.begin(); // Wire init, adding the I2C bus. Wire初始化, 加入i2c总线
Serial.begin(115200);
mfrc522.PCD_Init(); // Init MFRC522. 初始化 MFRC522
M5.Lcd.println("Please put the card\n\nUID:");
// LED port as output & set to "OFF"
pinMode(10, OUTPUT);
digitalWrite(10, HIGH);
}
void loop() {
// reset by B button push
if(M5.BtnB.wasPressed()){
esp_restart();
}
M5.update();
M5.Lcd.setCursor(40, 47);
if (!mfrc522.PICC_IsNewCardPresent() ||
!mfrc522.PICC_ReadCardSerial()) { //如果没有读取到新的卡片
delay(200);
return;
}
M5.Lcd.fillRect(42, 47, 240, 20, BLACK);
for (byte i = 0; i < mfrc522.uid.size;
i++) { // Output the stored UID data. 将存储的UID数据输出
M5.Lcd.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
M5.Lcd.print(mfrc522.uid.uidByte[i], HEX);
Serial.print(mfrc522.uid.uidByte[i], HEX);
// beep & LED on for 50ms
M5.Beep.tone(880);
digitalWrite(10, LOW);
delay(50);
M5.Beep.mute();
digitalWrite(10, HIGH);
}
M5.Lcd.println("");
Serial.println("");
}
M5Stackファミリーも後から出てくるハードの方が進化しています。
admin
M5StackからPCへの接続方法にはいろいろありますが、無線でなくても良い、つまりUSBで電源供給しているならばUSB経由のシリアルで接続するのが妥当そうです。
このときにシリアルポートを指定しないといけないですが、ポートをスキャンするサンプルがあったので使ってみました。
参考は、
https://garchiving.com/processing-auto-serial-port/
になります。
PC側はProcessingを使っていますが、12行目から21行目までがポート検出の該当スクリプトです。ポート指定方法としてnew Serialの第二引数に”/dev/tty.usbserial-54260147311″のように直接指定する方法もありますが、環境が変われば改めて設定しなければならないでしょうから、自動検出にはメリットがあります。
import processing.serial.*;
Serial myPort;
int x;
String[] comPort = myPort.list();
void setup(){
// 画面サイズ
size(256, 256);
int num = comPort.length;
for (int i=0; i<num; i++) {
try {
myPort = new Serial(this, comPort[i], 115200);
println(comPort[i]);
}
catch(Exception e) {
continue;
}
}
}
void draw(){
// 背景色を白に設定
background(255);
// XY座標を(x,100)に設定し、
// 幅50、高さ50の円を描画
ellipse(x,100,50,50);
}
void serialEvent(Serial p){
//変数xにシリアル通信で読み込んだ値を代入
x = p.read();
println(x);
}
M5Stack側は極めてシンプルなスクリプトで1秒ごとに異なる値を送るだけ。Processing側ではcircleの座標として扱っています。
#include
void setup(){
Serial.begin(115200);
}
void loop(){
Serial.write(100);
delay(1000);
Serial.write(200);
delay(1000);
}
admin