GoでAPI作成
vscodeで作業ディレクトリを作成して、とりあえず、hello worldを出力
ほとんどここはTSと同じ頭領でいけた
作業ディレクトリにDockerを導入していく
そのために必要なのは、Dockerfileとdocker-compose.ymlの二つが必要
docker-compose build
しようとしたら、コマンドを打つディレクトリを間違えてた
Dockerfileのファイル指定をちゃんと理解する必要がある
dockerの大まかな流れ
- buildをする
- buildしたかを確認する(buildできていたら、imagesが作られる)
- buildして生成したimagesを元にコンテナを作成する
この流れでdockerの上で開発できるようになる
Docker で "no such file or directory" が出た
go mod init
は何をしているのか??
go mod init ディレクトリ名
でいいのかな??
npm install
と同じ
go get
で必要なモジュールのインストールができる
npm add
と同じ
これでGoのAPIをdeployする
cloud run
とcloud functions
の違いは、functions
は関数をdeployするだけでcloud run
はコンテナをdeployするので、関数からDBまでDockerのコンテナをdeployしているのと同じイメージかも??
久しぶりにGo
を使って、遊んでたらgo mod tidy
なんてやつがCLIから出てきた
tidy
はいらないpackageや使わないpacckageを削除してくれるコマンド
go mod init
はローカルで実行するだけなら、適当でもいい
ちゃんとGitHub
で公開してやるなら、go mod init 'GitHubのURL'
例: github.com/kinjo1130/go-api
上記の感じでやっていけばいい
でも、定数を使ったらいいんじゃない?
JSでいうならconst
とか
「ポインタはなぜ必要なのか」という問いに答えるとするならば、「データを参照する際に、データが保持されているアドレスを渡して、意図せずにデータが変更されるのを防ぐため」と言うのが答えになります。
Goの構造体の補完はないのか?
TSみたいに型をつけたら、保管してくれるように
並列処理にはgoroutine
とchannel
の二つの理解が必須
並列処理をやっているときに、複数の処理が終わったら、次の処理に進みたいとかはあると思う
チャネルを使うことで、スレッド同士の値を橋渡しができる
sum := 0;
for _,v range s{
sum +=v
}
なんで_,v
になっているのかが気になったけど、これはfor
文の文法にある
GoにはTSでいうenum
がないので、自作した
type TaskStatis int
const (
Done TaskStatus = iota
Doing
)
type Todo struct {
id int
title string
status TaskStatus
}
func showTaskStatus(){
var todo Todo
todo.status = Done
}
const
とiota
を使って、実装する
iota
とは??
この記事によると、型なしの連番整数
を付与するらしい
init()
これはmain()
よりも先に実行されて、複数書くことができる
main()
はパッケージに一つしか書けない
init()
は複数書いても、区別されている
TSでas T
Goではx.(T)
var x interface{} = 3
x.(int) // true
x.(float32) //false
:=
は変数定義と再代入を同じやってくる
使い分けとしては、
// =だけを使う
var test string
test = "来週から始まる"
// :=を使う
func textReturn(){
return "来週から始まる"
}
test := textReturn()
cloud Runの料金について理解はできた
最小インスタンスを設定しておくと、コールドスタートにならない代わりにその時間も課金が発生するよってことか
だから、最初のリクエストが遅くてもいいなら、最小インスタンスを割り当てないくてもいい
この内容もだいぶわかるようになった
あとはポインタ周りやな
なんでそう使っているのかがイマイチ掴めない
必要性がわからない
type User struct {
Name string json:"name" xml:"name" form:"name" query:"name"
Email string json:"email" xml:"email" form:"email" query:"email"
}
e.POST("/users", func(c echo.Context) error {
u := new(User)
if err := c.Bind(u); err != nil {
return err
}
return c.JSON(http.StatusCreated, u)
// or
// return c.XML(http.StatusCreated, u)
})
構造体に対して上記のようにタグ付けをすることで、リクエストのContent-Typeとそのキーに基づいてデータを紐付けるが出来ます。(*context) Bindの使用方法はとても簡単で、タグ付けが行われている構造体のゼロ値のポインタを引数に取るだけです。 application/json や application/x-www-form-urlencoded で該当の値が送られてきた場合、よしなに構造体へのデータ格納を行ってくれます。
(*context) JSONが初めて出てきましたが機能としては(*context) Stringと大差はありません。構造体やマップ等を渡せばjsonへのエンコードを行い、ステータスコードとともにレスポンスへ書き込みます。
これも少し理解した
構造体タグを使うことで、jsonなど指定した形式でデータを扱うことができる
Bind
をして、使いたい形式にデータを変換して、JSON
でjson形式でレスポンスをしている
いまだに謎いのが、構造体とjsonの関係性だよね
あとはinterface型とかもイマイチ理解してない
TSでいうtype
やinterface
と同じぐらいの理解しかしてない
docker-coposeでvolums
を指定することで、コンテナを落としてもデータが永続的に残すことができる
Goの構造体において、フィールド名が小文字で始まっているとそれは非公開(プライベート)フィールドとなります。これは、そのフィールドが定義されているパッケージの外部からはアクセスできないことを意味します。そのため、非公開フィールドにjsonタグをつけても、外部からそのフィールドにアクセスできないため、このようなエラーメッセージが出ています。
これを解決するためには、フィールド名を大文字にして公開(パブリック)フィールドにする必要があります。その際、jsonタグを用いてJSON形式での名前を小文字にすることが一般的です。以下に示すように修正してみてください:
go
Copy code
type MyStruct struct {
Name string json:"name"
}
この例では、フィールドNameは公開されているため、パッケージ外からもアクセス可能です。また、JSONにエンコードされる際のキーは小文字のnameとなります。
知らんかった
FindById(id int) (User, error)関数は、指定されたIDを持つユーザーを探し、そのユーザーを返すか、エラーを返すという意味です。ここで、戻り値としてUserを返している理由は二つあります。
ポインタを使うことでメモリ効率が良くなる: Userが大きな構造体だった場合、そのコピーを作ると(つまり、値を直接返すと)メモリを大量に消費します。しかし、ポインタを使うと、オリジナルのUser構造体への参照だけを返すため、メモリ効率が良くなります。
nilを返すことが可能になる: もし該当するUserが見つからなかった場合やエラーが発生した場合、ポインタではnilを返すことが可能です。これは値そのものを返すとできないことです。この機能を利用すると、該当するユーザーが存在しない場合や何らかのエラーが発生した場合に、特別なUser値(例えば、IDが-1のユーザー)を用意する必要がなくなります。FindById(id int) (User, error)関数は、指定されたIDを持つユーザーを探し、そのユーザーを返すか、エラーを返すという意味です。ここで、戻り値としてUserを返している理由は二つあります。
これはなるほどおおおおって感じ
めっちゃ理解できる
usecase層でnewで初期化して、関数を実体化していくだけ
処理は書いてはいけない
具体的な処理は、repository層で描く