- 投稿日:2019-10-28T17:01:49+09:00
Go言語の構造体の基本
Go言語にはJavaなどの言語でいうクラスやというものがなく、構造体というデータをひとまとめにして扱うための仕組みを使ってクラスのような機能を提供します。
この構造体を使うことで、オブジェクト指向の継承のような実装を実現することが出来、Go言語の一つの大きな特徴になっています。
この記事では構造体の宣言の仕方から、実際にどのように扱われるのかまで見ていきます。
構造体の基本
構造体の宣言
Go言語の構造体は以下のように変数として宣言して使用できます。
var japanese struct { name string age int } japanese.name = "hanako" japanese.age = 23 fmt.Println(japanese)構造体は変数だけではなく、型として宣言することもでき、こちらの方がより広く使われています。
type person struct { name string age int } studentA := person{ name: "Taro", age: 20, } fmt.Println(studentA)構造体の型がクラスで、定義した構造体の型で変数を宣言するのがインスタンス変数を宣言するのに似ています。
また、構造体に構造体を埋め込むことが可能で、これにより継承を実現しています。継承したい構造体(親クラスに当たるもの)を構造体の中に定義します。
オブジェクト指向言語と同じように、親クラスに当たる構造体のフィールドには子クラスに当たる構造体からアクセスすることが可能です。
func main() { studentA := person{ name: "Taro", age: 20, } taro := japanese{ language: "Japanese", country: "Japan", person: studentA, } fmt.Println(taro) fmt.Println(taro.person.name) //埋め込まれている構造体の要素にアクセスできる } type person struct { name string age int } type japanese struct { language string country string person person }構造体はクラスに相当する役割を果たすため、当然メソッドも定義できます。構造体にどうメソッドを定義すればいいのか見ていきましょう。
構造体にメソッドを定義する
構造体にメソッドを定義するには、定義先の構造体をレシーバに持つ関数を定義する必要があります。
実際に見てみましょう。これが構造体にメソッドを定義する例です。
type person struct { name string age int } func (p person) selfIntro() { fmt.Printf("My name is %v. I'm %v years old.", p.name, p.age) }ご覧のように、personをレシーバに持つselfIntroというメソッドを定義しています。selfIntro()メソッド内部では、レシーバとして受け取った構造体が持つ変数にアクセスし、その変数の値を出力しています。
func main() { studentA := person{ name: "Taro", age: 20, } fmt.Println(studentA) studentA.selfIntro() //出力結果: My name is Taro. I'm 20 years old. }これが実際に使用する場合の使用例です。
構造体の使用例
ここまでで構造体の基本について見てきました。ここからは構造体を使用することでコードをより読みやすくできる例をご紹介します。
以下の構造体は、天気予報の情報を定義している構造体の型です。現時点では最高気温と最低気温、緯度経度による位置情報が入っています。
type wheatherReport struct { high, low float64 latitude, longitude float64 }現時点では、この二つだけなのでまだ分かりやすいでしょう。しかし、この構造体に最高湿度と最低湿度、降水確率など新しい情報を入れようとすると、ややこしくなってしまいます。
type wheatherReport struct { highTemperature, lowTemperature float64 highHumidity, lowHumidity float64 latitude, longitude float64 }新たに構造体を定義し、構造体を埋め込むことでこの問題を解決することが出来ます。
func main() { nara := wheatherReport{ temperature: temperature{high: 21.2, low: 11.0}, humidity: humidity{high: 55, low: 33}, } fmt.Println(nara.humidity.high) fmt.Println(nara.temperature.high) } type temperature struct { high, low float64 } type humidity struct { high, low float64 } type location struct { latitude, longitude float64 } type wheatherReport struct { temperature temperature humidity humidity location location }どうでしょう、一気に読みやすくなったかと思います。Go言語のコードを読んでいると、至る所で構造体が使われているので、しっかりと理解しておきましょう。
おまけ:構造体を初期化するコンストラクタ関数
オブジェクト指向の言語には、インスタンスをNewで作成した時に呼び出される機能があります。Pythonではinit、Rubyではinitialize、PHPでは__construct()です。
しかし、そのような仕組みがGoにはありません。その代わりとなるものがコンストラクタ関数です。
コンストラクタ関数は名前の先頭にnewという名前をつけて宣言するという慣習があります。
func newTemperature(high, low float64) temperature { return temperature{high, low} }このようにして、コンストラクタ関数で構造体を初期化するというやり方があるので覚えておくとよいでしょう。
それでは、最後までお読みいただきありがとうございました。
- 投稿日:2019-10-28T09:00:59+09:00
初心者でもDockerでAmazonLinux+Go(Echo)+Mysqlの環境構築しつつ簡単なAPIを作って動かす
DockerでAmazonLinux+Go+Mysqlの環境構築する
PHPerだったけど今度はGoやっていくので環境をDockerで作ってそこで簡単なAPIをGoのフレームワーク「Echo」で作っていく
環境
- Docker Desktop on Windows:19.03.1
- AmazonLinux(イメージ:https://hub.docker.com/_/amazonlinux )
- MySQL:8.0:(イメージ:https://hub.docker.com/_/mysql )
- Go:1.13.3
- labstack/echo
- go-sql-driver/mysql
ちなみに作業環境はWindows10 Proのi7メモリ32GBノートPCです
ディレクトリ構成
|-Dockerfile |-docker-compose.yml |-./src |-main.goDockerfile
まずAmazonLinuxにGoをインストールしたイメージを作成する
FROM amazonlinux:latest ENV GOPATH /go ENV PATH /usr/local/go/bin:/go/bin:$PATH WORKDIR /usr/src # go install RUN yum update -y \ && yum install -y tar \ && yum install -y gzip \ && curl -OL https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz \ && tar -C /usr/local -xzf ./go1.13.3.linux-amd64.tar.gz \ # git install for go get command RUN yum install -y git # go library RUN go get github.com/go-sql-driver/mysql \ && go get github.com/labstack/echo CMD ["go", "run", "main.go"]イメージ生成(docker build -t )
イメージ名は何でもいいですけどここでは
test-aws_go-imgとします(.は同ディレクトリを指す)docker build -t test-aws_go-img .docker-compose.yml
上記でビルドして作成したイメージ(
test-aws_go-img)をdocker-compose.ymlで指定docker-compose.ymlversion: '3.7' services: test-aws_go-img: build: . container_name: test_app # わかりやすいコンテナ名にしておく(任意) ports: - 8080:8080 db: container_name: test_db # わかりやすいコンテナ名にしておく(任意) image: mysql:8.0 command: --default-authentication-plugin=mysql_native_password # 従来の認証方式にしておく volumes: - db-store:/var/lib/mysql - ./logs:/var/log/mysql environment: - MYSQL_DATABASE=test_todo - MYSQL_ROOT_PASSWORD=password - TZ=Asia/Tokyo ports: - 3307:3306 volumes: # データの永続化 db-store:これでDocker周りは完了
main.go
アクセスするとテーブルに登録されているデータをJSONで返すようなかんたんなAPIを作る
main.gopackage main import ( "database/sql" "fmt" "net/http" _ "github.com/go-sql-driver/mysql" "github.com/labstack/echo" ) // JSON用の構造体を定義 type Task struct { ID int `json:"id"` Name string `json:"name"` } func main() { e := echo.New() e.GET("/tasks", getTasks) e.Start(":8080") } func dbConnect() *sql.DB { // DB接続処理 db, err := sql.Open("mysql", "root:password@tcp(test_db)/test_todo") if err != nil { panic(err.Error()) } return db } func getRows(db *sql.DB) *sql.Rows { rows, err := db.Query("SELECT id,name FROM tasks") if err != nil { panic(err.Error()) } return rows } func getTasks(c echo.Context) error { // DB接続 db := dbConnect() defer db.Close() rows := getRows(db) defer rows.Close() task := Task{} var results []Task for rows.Next() { err := rows.Scan(&task.ID, &task.Name) if err != nil { panic(err.Error()) } else { results = append(results, task) } } return c.JSON(http.StatusOK, results) }Docker起動
動くか確認するためにバックグラウンドのオプションはつけないで普通に起動
docker-compose up無事起動したら次に確認用のサンプルデータを入れていく
DBへ接続してデータを入れる
別の画面を開いて(Windowsならコマンドプロンプトとか)MySQLのコンテナの中に入る
docker exec -it test_db bashMySQLへログイン(パスワードは上記で設定した
password)# mysql -u root -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 9 Server version: 8.0.18 MySQL Community Server - GPL Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use test_todo; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed以下のSQLを流す(コピペで可)
SET NAMES utf8; SET time_zone = '+00:00'; SET foreign_key_checks = 0; SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; SET NAMES utf8mb4; CREATE DATABASE `test_todo` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; USE `test_todo`; DROP TABLE IF EXISTS `tasks`; CREATE TABLE `tasks` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; INSERT INTO `tasks` (`id`, `name`) VALUES (1,"go"), (2, "php"), (3, "java"), (4, "html"), (5, "css");念の為入ったか確認しておく
mysql> select * from tasks;URLを叩いてJSONが帰ってくるか確認
準備ができたのでターミナルやらで
curlコマンドを叩くcurl -s http://localhost:8080/tasksすると以下のようにJSONでデータが取得出来る
[{"id":1,"name":"go"},{"id":2,"name":"php"},{"id":3,"name":"java"},{"id":4,"name":"html"},{"id":5,"name":"css"}]以下はChromeからアクセスした際の様子
おわり
- 80%くらいの確率で動くと思うんですが動かなかったらおしえてほしいです
- それ以外でもこうしたほうがいい等あればコメント下さい
参考URL
- https://docs.docker.com/compose/compose-file/
- https://stackoverflow.com/questions/57566060/panic-dial-tcp-127-0-0-13306-connect-connection-refused
- https://tech.speee.jp/entry/2017/08/22/110000
- https://qiita.com/K-juju/items/f6d0eedb9aee5714cb73
- https://shinter8823.hatenablog.com/entry/2019/07/18/015051
- https://qiita.com/zembutsu/items/9e9d80e05e36e882caaa
- https://omohikane.com/golang_on_dokcer/
- https://designsupply-web.com/knowledgeside/3325/
- https://qiita.com/lkeix_/items/b291eb9cebc76deeb916
- https://qiita.com/ShinyaIshikawa/items/fede44cee7c71721247a
などなど

