20210505のGoに関する記事は5件です。

【Go言語】構造体を要素に持つスライスの作成・要素追加・初期化方法まとめ

スライスとは可変長の配列のことです。 Go言語でWeb APIを実装する場合(= JSONレスポンスを作成する場合)などで以下のような『構造体を要素に持つスライス』を作成する機会があります。 users = [ { "name": "Suzuki", "age": 20 }, { "name": "Tanaka", "age": 21 }, ] 今回は、構造体を要素に持つスライスの作成方法についてまとめます。 構造体を要素に持つスライスの作成(変数定義)方法 スライスの作成は、型[]T(型Tのスライスを表す)を利用する方法 と、make関数を利用する方法があります。1 2 User構造体のスライスをusers変数として扱う場合、スライスの作成方法には以下の種類があります。 make関数を利用する方法 make([]User, 0) []を利用する方法 users := []User{} var users []User var users []User = []User{} 以下からわかるように、上記のスライス作成方法はすべて同じ結果になります。 package main import "fmt" type User struct { name string age int } func main() { users_1 := []User{} var users_2 []User var users_3 []User = []User{} users_4 := make([]User, 0) fmt.Println(users_1, len(users_1), cap(users_1)) // [] 0 0 fmt.Println(users_2, len(users_2), cap(users_2)) // [] 0 0 fmt.Println(users_3, len(users_3), cap(users_3)) // [] 0 0 fmt.Println(users_4, len(users_4), cap(users_4)) // [] 0 0 } スライスに構造体を要素として追加する方法 スライスへ新しい要素を追加するには、append関数を利用します。3 package main import "fmt" type User struct { name string age int } func main() { users := []User{} user_1 := User{name: "Suzuki", age: 20} users = append(users, user_1) fmt.Println(users) // [{Suzuki 20}] user_2 := User{name: "Tanaka", age: 21} users = append(users, user_2) fmt.Println(users) // [{Suzuki 20} {Tanaka 21}] } 構造体の初期化方法の詳細は【Go言語】構造体の初期化方法の種類まとめで解説しているのであわせてご覧になってください。 参考: スライスをJSONに変換する方法 スライスをJSONに変換する場合は以下のようにします。 package main import ( "encoding/json" "fmt" ) // jsonで構造体を扱えるようにするため、構造体のフィールド名は大文字にする // jsonタグでJSONのプロパティ名を設定できる type User struct { Name string `json:"name"` Age int `json:"age"` } func main() { users := []User{} user_1 := User{Name: "Suzuki", Age: 20} users = append(users, user_1) fmt.Println(users) // [{Suzuki 20}] user_2 := User{Name: "Tanaka", Age: 21} users = append(users, user_2) fmt.Println(users) // [{Suzuki 20} {Tanaka 21}] bytes, _ := json.Marshal(users) fmt.Println(string(bytes)) // [{"name":"Suzuki","age":20},{"name":"Tanaka","age":21}] } 参考: スライスの作成と初期化をまとめて行う方法 以下のようにすると、スライスの作成と初期化(= 要素となる構造体をセット)を1行で行えます。 package main import ( "fmt" ) type User struct { name string age int } func main() { users := []User{{"Suzuki", 20}, {"Tanaka", 21}} fmt.Println(users) // [{Suzuki 20} {Tanaka 21}] } さいごに 認識違いや補足があればコメントいただけると助かります。 A Tour of Go『Creating a slice with make』 ↩ A Tour of Go『Slices』 ↩ A Tour of Go『Appending to a slice』 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Arudino を Go (TinyGo) で開発しよう

ゴール Go でマイコンボードや wasm の開発ができる TinyGo が何かわかる TinyGo で Arduino を動かせるようになる 背景 既存の Arduino 等のマイコンボード向けの開発言語は、C ないし C++ となっており、それ以外に選択肢はあまりありませんでした。 しかし近年、マイコンボード向けの開発言語も、徐々に選択肢が広がってきています。 今日紹介する TinyGo 以外でも、Rust や Micro Python 等もよく聞くようになっています。 そんな感じで組み込み分野も、プログラミング言語の選択肢が広がっているのはよいことだと思います。 今回は、個人的におすすめの、Go から 派生した TinyGo というプログラミング言語 を紹介します。 使用するマイコンボードは、比較的ポピュラーな Arduino を使用してみました。 TinyGo とは TinyGo は Go をマイコン等や wasm 等の小さな環境で使用することができるプログラミング言語です。 TinyGo is a project to bring the Go programming language to microcontrollers and modern web browsers by creating a new compiler based on LLVM. tinygo.org 使用できるマイコンボード 記事執筆時点の ver0.17.0 では以下のボードに対応しています。 (記事も適宜メンテする予定) 今回取り上げる Arduino 以外だと、Adafruit の Feather シリーズや、 SeeedStudio の Xiao が比較的安価で性能が良いのでおすすめです。 Adafruit CLUE Adafruit Circuit Playground Bluefruit Adafruit Circuit Playground Express Adafruit Feather M0 Adafruit Feather M4 Adafruit Feather STM32F405 Adafruit Feather nRF52840 Adafruit ItsyBitsy M0 Adafruit ItsyBitsy M4 Adafruit ItsyBitsy-nRF52840 Adafruit Matrix Portal M4 Adafruit Metro M4 Express AirLift Adafruit PyBadge Adafruit PyGamer Adafruit PyPortal Adafruit QtPy Adafruit Trinket M0 Arduino MKR1000 Arduino Mega 2560 Arduino Nano Arduino Nano33 IoT Arduino Uno Arduino Zero BBC micro:bit Bluepill Digispark Dragino LGT-92 ESP32 - Core board ESP32 - mini32 ESP8266 - NodeMCU ESP8266 - d1mini Game Boy Advance HiFive1 RevB Nintendo Switch Nucleo F103RB PCA10031 PCA10040 PCA10056 Particle Argon Particle Boron Particle Xenon PineTime ProductivityOpen P1AM-100 STM32 Nucleo F722ZE STM32 Nucleo L552ZE STM32F4 Discovery Seeed Seeeduino XIAO Seeed Wio Terminal Sipeed MAix Bit Teensy 3.6 Teensy 4.0 X9 Pro Smartwatch nRF52840-MDK nRF52840-MDK-USB-Dongle nice!nano v1.0 reel board TinyGo のインストール TinyGo 以下のウェブサイトへ、各 OS ごとのインストール方法が記載されています。 https://tinygo.org/getting-started/ こちらに従い、tinygo コマンドが実行できるようにしてください。 Arduino 用の書き込み環境のインストール avr-gcc Arduino については、別途、マイコンボードへ書き込むためのソフトをインストールしてください。 https://blog.zakkemble.net/avr-gcc-builds/ Arduino の L チカ Pin を指定するシンボルの定義 マイコンボードの各 Pin の定義は公式の以下のページに記載されています。 https://tinygo.org/microcontrollers/machine/arduino/ サンプルコード 内臓の LED を点滅させるコードは以下のように書けます。 main.go package main import ( "machine" "time" ) func main() { var led machine.Pin led = machine.LED led.Configure(machine.PinConfig{Mode: machine.PinOutput}) for { println("running...") led.Low() time.Sleep(time.Millisecond * 300) led.High() time.Sleep(time.Millisecond * 300) } } } build して書き込む 以下のコマンドを実行してください。 その際にインストールした avr-gcc に Path が通っていないと怒られるので、 その場合は、path/to/avr-gcc-10.0.10-xxx/bin な場所へ Path を通してください。 --port の指定については、Windows の場合はデバイスマネージャーの「ポート(COM と LPT)」を見ればわかります。 コマンドの実行時、書き込み用のソフト (avrdude) の実行時メッセージが沢山出力されますが、 成功時は以下のように出力されます。 (たまに書き込みが 25% 程度でロックされ成功しないことがありますが、大抵は接続する USB ポートを変更すれば直ります) $ tinygo flash --target arduino --port COM3 avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% -0.00s avrdude: Device signature = 0x1e950f (probably m328p) avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: reading input file "C:\Users\aki01\AppData\Local\Temp\tinygo190349755\main.hex" avrdude: writing flash (774 bytes): Writing | ################################################## | 100% 0.16s avrdude: 774 bytes of flash written avrdude: verifying flash memory against C:\Users\aki01\AppData\Local\Temp\tinygo190349755\main.hex: avrdude: load data flash data from input file C:\Users\aki01\AppData\Local\Temp\tinygo190349755\main.hex: avrdude: input file C:\Users\aki01\AppData\Local\Temp\tinygo190349755\main.hex contains 774 bytes avrdude: reading on-chip flash data: Reading | ################################################## | 100% 0.14s avrdude: verifying ... avrdude: 774 bytes of flash verified avrdude: safemode: Fuses OK (E:00, H:00, L:00) avrdude done. Thank you. print (標準出力) の出力先について TinyGo は、println や fmt.Printf 等の出力先が、シリアルポートとなっています。 よって、TeraTerm 等で接続することで以下のようにプリントデバッグをすることもできます。 まとめ TinyGo を使うと、普段 Go を書いている感覚でマイコンボードの開発ができる 様々なボードに対応していて、ポピュラーな Arduino にも対応している build ~書き込みはコマンドひとつでできるので簡単
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go言語】構造体の初期化方法パターンまとめ

Go言語の構造体の初期化方法には以下のパターンがあります。 ポインタ型を使わない場合 『変数定義 → フィールド値のセット』と2段階で初期化する方法 構造体リテラルでフィールド値をセットする方法 ポインタ型を使う場合 アドレス演算子と構造体リテラルを利用する方法 newを利用する方法 以下では各方法について紹介をします。 ポインタ型を使わない場合 ポインタ型を使わない場合の構造体の初期化方法について説明します。 『変数定義 → フィールド値のセット』と2段階で初期化する方法 構造体の変数を定義し、定義した変数に構造体のフィールド値をセットする方法です。 変数を定義してからフィールド値をセットするため、複数行で構造体の初期化をします。 User構造体をuser変数として扱う場合、変数定義の方法には以下の種類があります。 変数定義の方法 user := User{} var user User = User{} var user User 以下の結果からわかるように、上記の変数定義の方法はすべて同じ意味をもちます。 package main import "fmt" type User struct { name string age int } func main() { user_1 := User{} var user_2 User = User{} var user_3 User fmt.Println(user_1) // { 0} fmt.Println(user_2) // { 0} fmt.Println(user_3) // { 0} } フィールド値のセットは[変数].[フィールド名] = [値]で行います。 package main import "fmt" type User struct { name string age int } func main() { user := User{} user.name = "Suzuki" user.age = 20 fmt.Println(user) // {Suzuki 20} } 構造体リテラルでフィールド値をセットする方法 構造体リテラル(Structure Literals)を利用した場合、1行で構造体の初期化ができます。 構造体リテラルを利用したフィールド値のセット方法には以下の2種類があります。 フィールド名を指定する方法 フィールド名を指定しない方法 フィールド名を指定する場合、任意のフィールドを任意の順番でセットできます。 package main import "fmt" type User struct { name string age int } func main() { user_1 := User{name: "Suzuki", age: 20} fmt.Println(user_1) // {Suzuki 20} user_2 := User{age: 20, name: "Suzuki"} fmt.Println(user_2) // {Suzuki 20} user_3 := User{name: "Suzuki"} fmt.Println(user_3) // {Suzuki 0} } フィールド名を指定しない場合、構造体すべてのフィールドに対して値をセットする必要があります。 また構造体リテラルに記述するフィールドは、構造体での定義順と合わせる必要があります。 package main import "fmt" type User struct { name string age int } func main() { user_1 := User{"Suzuki", 20} fmt.Println(user_1) // {Suzuki 20} // NG(全てのフィールドを定義していないため) user_2 := User{"Suzuki"} fmt.Println(user_2) // too few values in User{...} // NG(フィールドの記述順が正しくないため) user_3 := User{20, "Suzuki"} fmt.Println(user_3) // cannot use 20 (type untyped int) as type string in field value // cannot use "Suzuki" (type untyped string) as type int in field value } ポインタ型を使う場合 ポインタ型を使う場合の構造体の初期化方法について説明します。 アドレス演算子と構造体リテラルを利用する方法 アドレス演算子(&)と構造体リテラルを利用して&{}という形で構造体の初期化をする方法です。 構造体リテラルを利用しているため、1行で構造体の初期化ができます。 構造体リテラルの記述方法は、さきほど『構造体リテラルでフィールド値をセットする方法』の項目で紹介したルールと同じです。 package main import "fmt" type User struct { name string age int } func main() { user_1 := &User{name: "Suzuki", age: 20} fmt.Println(user_1) // &{Suzuki 20} user_2 := &User{age: 20, name: "Suzuki"} fmt.Println(user_2) // &{Suzuki 20} user_3 := &User{name: "Suzuki"} fmt.Println(user_3) // &{Suzuki 0} user_4 := &User{"Suzuki", 20} fmt.Println(user_4) // &{Suzuki 20} // NG(全てのフィールドを定義していないため) user_5 := &User{"Suzuki"} fmt.Println(user_5) // too few values in User{...} また、以下の結果を見てわかる通り、アドレス演算子を利用して構造体の初期化をした場合、変数の型はポインタ型(*)となります。 package main import "fmt" type User struct { name string age int } func main() { // ポインタ型 user_1 := &User{name: "Suzuki", age: 20} fmt.Println(user_1) // &{Suzuki 20} fmt.Printf("%T\n", user_1) // *main.User // ポインタ型じゃない user_2 := User{name: "Sato", age: 20} fmt.Println(user_2) // {Sato 20} fmt.Printf("%T\n", user_2) // main.User } 参考: アドレス演算子を利用した、構造体の初期化メソッド 以下のようにするとアドレス演算子を利用した構造体の初期化をメソッドにできます。 package main import "fmt" type User struct { name string age int } func newUser(name string, age int) *User { return &User{name: name, age: age} } func main() { user := newUser("Suzuki", 20) fmt.Println(user) // &{Suzuki 20} } 参考: ポインタ型の構造体のフィールドへのアクセス方法について ポインタ型の構造体のフィールドへアクセスする場合(*user).nameのように記述します。 しかしGo言語ではuser.nameとも記述可能です。1 package main import "fmt" type User struct { name string age int } func main() { user := &User{name: "Suzuki", age: 20} fmt.Println((*user).name) // Suzuki fmt.Println(user.name) // Suzuki } newを利用する方法 newを利用してポインタ型で構造体を初期化する方法です。 user := new(User)はuser := &User{}と同じ意味になります。 つまり、newを利用した場合は『変数定義 → フィールド値のセット』と2段階で初期化することになります。 package main import "fmt" type User struct { name string age int } func main() { user_1 := new(User) user_1.name = "Suzuki" user_1.age = 20 fmt.Println(user_1) // &{Suzuki 20} // NG(newは1行で初期化できないため) user_2 := new(User{"Suzuki", 20}) fmt.Println(user_2) // User{...} is not a type } 参考: newを利用した、構造体の初期化メソッド 以下のようにするとnewを利用した構造体の初期化をメソッドにできます。 package main import "fmt" type User struct { name string age int } func newUser(name string, age int) *User { user := new(User) user.name = name user.age = age return user } func main() { user := newUser("Suzuki", 20) fmt.Println(user) // &{Suzuki 20} } まとめ 構造体の初期化方法まとめ 構造体の変数定義は『s := S{}』『var s S = S{}』『var s S』の3パターン 構造体リテラルでフィールド値をセットできる 構造体リテラルを利用すると1行で構造体の初期化ができる 構造体リテラルでフィールド名を定義しない場合、構造体での定義順ですべてのフィールドをセットする必要がある newやアドレス演算子で構造体を定義した場合、ポインタ型になる 認識違いや補足があればコメントいただけると助かります。 参考 [Go] ポインタについて学ぶ(基本的なところ) A Tour of Go『More types: structs, slices, and maps.』 Goでよく見るnewとNewを調べたときのメモ 【Go】基本文法③(ポインタ・構造体) A Tour of Go『Pointers to structs』 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu 20.04 に最新のprotobufを入れてprotocでGoのコードを生成するまで

前書き 死ぬほど苦戦しました。 protobufの入れ方が幾つかあるのですが、上手くいかないものが沢山あり、ようやくインストールする方法が見つかりました。 前提 go version go1.13.8 linux/amd64 NAME="Ubuntu" VERSION="20.04.2 LTS (Focal Fossa)" protobuf sudo apt install protobuf-compiler だとバージョンが古すぎてAPIv2が使えません。 公式のリポジトリからコードを引っ張ってきてインストールすることになります。 sudo apt install autoconf automake libtool curl make g++ unzip -y git clone https://github.com/google/protobuf.git cd protobuf git submodule update --init --recursive ./autogen.sh configure make make check sudo make install sudo ldconfig 引用 Ubuntu 20.04に最新のProtobufをインストールする makeやmake check等は劇遅です。 環境によっては1時間ほどかかるかも。 ターミナルを一度再起動して protoc --version で最新バージョンになっていればOKです。 Goのライブラリ go install google.golang.org/grpc go install github.com/golang/protobuf/protoc-gen-go go install google.golang.org/grpc/cmd/protoc-gen-go-grpc PAHTが通っていないのであれば protoc-gen-go-grpc: program not found or is not executable Please specify a program using absolute path or make sure the program is available in your PATH system variable このようなエラーが出る場合はPATHが通っていないので ~/.bashrcを開くor作成して export GOPATH=$HOME/go export PATH=$PATH:$GOPATH/bin を追記 以上 後は任意のprotoに対してprotocコマンドを実行。 以上で生成できました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Go 自分用メモ

command-line go version # check install go run . # compile& excute go mod tidy # importしているモジュールの準備 go help # help go mod init example.com/greetings # moduleの新規作成 #↑ 本来は作成するモジュールをダウンロードできるパスを指定する # packageパスの修正 # greetingsをローカルから読むようにする  go mod edit -replace=example.com/greetings=../greetings # go.modに以下行が追加される # replace example.com/greetings => ../greetings ファイル modファイル: dependencies (依存モジュール)が記載されている 文法 := 変数の宣言と代入を一括で行える 以下2つは同じことをしている。(型は右辺と同じものを利用) message := fmt.Sprintf("Hi, %v. Welcome!", name) var message string message = fmt.Sprintf("Hi, %v. Welcome!", name) 2次元配列 動的生成 (https://go-tour-jp.appspot.com/moretypes/18 で作成) func Pic(dx, dy int) [][]uint8 { ret := make([][]uint8, dy, dy) for y := range(ret) { ret[y] = make([]uint8, dx, dx) for x := range(ret[y]) { ret[y][x] = uint8(x ^ y) } } return ret } 値指定 arr := [][]int { {1,2,3}, {3,2,1}, } fmt.Print(arr) レシーバ関数の場合の自動変換 レシーバ関数の場合はポインタ・実体の自動変換が行われる。 var v Vertex fmt.Println(AbsFunc(v)) // OK fmt.Println(AbsFunc(&v)) // Compile error! var v Vertex fmt.Println(v.Abs()) // OK p := &v fmt.Println(p.Abs()) // OK ※ https://go-tour-jp.appspot.com/methods/7 より
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む