
前々回heap、前回listとGoの標準ライブラリのcontainerを練習。今回はcontainerの最後の一つ ring です。しかし似たお名前のRingBufferがTinyGoのMachineパッケージの中に存在。今回は2つを比較してから、標準ライブラリのringの方をmicro:bit上で練習してみます。
※「GoにいればGoに従え」Go関連記事の総Index
go標準ライブラリのringとTinyGoのRingBuffer
ringもRingBufferもリングの形のデータ保持構造ではあるのですが、その適用は大分異なるものです。まず go の standard library のringについてのドキュメントは以下にあります。
一方 TinyGo の machineパッケージの中の RingBuffer についてのドキュメントは以下です。
Go素人が、勝手にほんわかしたところをまとめると以下の表のようになるのではないかと。知らんけど。
| container/ring | Machine package RingBuffer | |
|---|---|---|
| データ型 | Any | byte |
| データ書き込み | .Valueへ代入 | Put() |
| フル時書き込み動作 | 上書き | フルでは書き込み不可 |
| データ読み出し | .Value読み出し | Get() |
| 空読み動作 | nilが返る | エンプティでは読み出し不可 |
| リングアクセス | 双方向 | 単方向 |
TinyGoのRingBufferのお方は、いかにもUARTなどで通信したときの値などを一時バッファリングするための構造に見えます。「不可」と書かれているところは2番目の戻り値にfalseが返ります。それに対して標準ライブラリのringは、前回のlist構造の拡張的なものです。先へ先へと進んでいくと先頭に戻ってしまう、前へ前へと戻っていくと末尾へ戻ってしまう双方向のリストです。
これだけ性格が違うのでお名前は似ていても使い分けは大丈夫だあ。ホントか?
今回実験のTinyGoソースコード
今回のソースも御本家Go様の例題ソースをチョイ変です。殊更に Any な型のデータが突っ込めるぜという点、書き込んでないところを読み出すと<nil>だけれども、という点を「強調」してみました。
package main
import (
"container/ring"
"fmt"
)
func main() {
rB := ring.New(3)
nB := rB.Len()
fmt.Println("Ring Len=", nB)
rB.Value = 1
rB = rB.Next()
rB.Value = "abc"
rB = rB.Next()
for elem := 0; elem < nB; elem++ {
fmt.Println(elem, " : ", rB.Value)
rB = rB.Next()
}
}
実験結果
上記のソースをビルドしてUSB接続したターゲット機BBC micro:bit v2 に書き込むコマンドラインは以下です。
$ tinygo flash --target microbit-v2
シリアルモニタで観察した動作は以下です。
最初の要素は未初期化なので <nil>、次は先頭に戻って整数で1、その次は文字列で abc と。ring してますなあ。
RingBufferの方も練習しておかないと。また次回か。
