#はじめに
Go言語をさわりたくてチュートリアルをやりましたが、全部英語でした。
せっかくなので日本語版を作りました。
内容はほぼ一緒(なはず)で、最低限これでわかるであろうの感覚で書いたので
端折ってるところは多々ありますが参考になればうれしいです。
#環境
- Windows10
- visual studio code
- Go言語バージョン 1.16.6 (現時点で最新)
#Go言語をインストール
ここからインストール
インストールが終わるとgoコマンドが打てるようになる。
#チュートリアル:Goを使い始める(Tutorial: Get started with Go)をやってみる
チュートリアル:Goを使い始める
任意のディレクトリを作る。
→デスクトップにgo/helloというフォルダを作成
VScodeのターミナルでモジュールを初期化する。
go mod initで行うが、最初はこれをやるというおまじないという感覚でよさそう。
C:\Users\ryouta\Desktop\go\hello>go mod init example.com/hello
go: creating new go.mod: module example.com/hello
go.modというファイルが出来た。
モジュールを管理するファイルらしい。たくさん触ることになりそうな予感。
module example.com/hello
go 1.16
hello worldを出力するファイルを作る。
ファイルは普通に作った。
ソースはチュートリアルから指定のものを張り付けた。
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
go run コマンドで実行
PS C:\Users\ryouta\Desktop\go\hello> go run .
Hello, World!
間隔を掴むため色々実験。ソースを変えてgo runすると色々なエラーが出た。
//main→aaaへ変更
go run: cannot run non-main package
//packageの行をコメントアウト
hello.go:3:1: expected 'package', found 'import'
//fmt.Printlnの行をコメントアウト
# example.com/hello
.\hello.go:3:8: imported and not used: "fmt"
//func main()をfunc Main()へ変更
# example.com/hello
runtime.main_main·f: function main is undeclared in the main package
###外部パッケージの使い方
Goにはいろいろなパッケージがありその中には便利な関数が用意されているようだ。
例えばこのrsc.io/quoteパッケージを見ると
func Glass()文字列
func Go()文字列
func Hello()文字列
func Opt()文字列
ということわざを返却する関数を提供している。
デモンストレーション用の関数でしょう。
一応全部使ってみる。
流れとしては、goファイル内でimportしたものをgoコマンドで取り込み、その後実行できるようになる。
package main
import "fmt"
import "rsc.io/quote" //追加
func main() {
fmt.Println(quote.Hello()) //修正
}
go mod tidyコマンドでモジュールを追加したり消したりしてくれる。
C:\Users\ryouta\Desktop\go\hello>go mod tidy
go: finding module for package rsc.io/quote
go: downloading rsc.io/quote v1.5.2
go: found rsc.io/quote in rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
go runで実行する。
PS C:\Users\ryouta\Desktop\go\hello> go run .
こんにちは世界。
そのほかの関数も使ってみる。
// fmt.Println(quote.Glass())に修正
PS C:\Users\ryouta\Desktop\go\hello> go run .
I can eat glass and it doesn't hurt me.
// fmt.Println(quote.Go())に修正
PS C:\Users\ryouta\Desktop\go\hello> go run .
Don't communicate by sharing memory, share memory by communicating.
// fmt.Println(quote.Opt())に修正
PS C:\Users\ryouta\Desktop\go\hello> go run .
If a program is too slow, it must have a loop.
うん、ことわざの意味はよくわかってないけど、動きは分かった。
#チュートリアル:Goモジュールを作成する(Tutorial: Create a Go module)をやってみる
チュートリアル:Goモジュールを作成する
任意のディレクトリを作る。
→デスクトップにgo/greetingsというフォルダを作成
ターミナルでモジュールを初期化する。
C:\Users\ryouta\Desktop\go\greetings>go mod init example.com/greetings
go: creating new go.mod: module example.com/greetings
greeetings.goというファイルを作り、ソースを張り付ける。
package greetings
import "fmt"
// Helloは、指定された人の挨拶を返します。
func Hello(name string) string {
//メッセージに名前を埋め込む挨拶を返します。
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message
}
message:の : は宣言と初期化を一括で行うときに使う。
#チュートリアル:別のモジュールからコードを呼び出す(Call your code from another module)
別のモジュールからコードを呼び出す
上記で作ったhello.goに以下を張り付ける
package main
import (
"fmt"
"example.com/greetings"
)
func main() {
// Get a greeting message and print it.
message := greetings.Hello("Gladys")
fmt.Println(message)
}
ここで go mod tidyしてモジュールを読み込もうとすると以下のエラーとなる。
PS C:\Users\ryouta\Desktop\go\hello> go mod tidy
go: finding module for package example.com/greetings
exeample.com/hello imports
example.com/greetings: cannot find module providing package example.com/greetings: unrecognized import path "example.com/greetings": reading https://example.com/greet
go mod tidyは公開されているモジュールの中からさがすので、example.com/greetingsが見つからないためにエラーになった。
本番環境ではexample.com/greetingsを公開状態にする必要があるようだが、現状はローカル環境だけに存在しているので、
向き先をローカルへ向ける必要がある。
PS C:\Users\ryouta\Desktop\go\hello> go mod edit -replace example.com/greetings=../greetings
mod editはgo.modを直接編集するコマンドで、-replaceは置き換えするオプションだ。
単純にexample.com/greetingsは../greetingsに置き換えてね、ってだけ。
go.modを見てみると以下のように更新されていることが確認できる。
module exeample.com/hello
go 1.16
replace example.com/greetings => ../greetings
go mod tidyでモジュールを読み込む。
PS C:\Users\ryouta\Desktop\go\hello> go mod tidy
go: found example.com/greetings in example.com/greetings v0.0.0-00010101000000-000000000000
再度go.modを見てみると以下のように更新されている。
module exeample.com/hello
go 1.16
replace example.com/greetings => ../greetings
require example.com/greetings v0.0.0-00010101000000-000000000000
v0.0.0-00010101000000-000000000000 は借採番された疑似バージョン。
これで動かせるようだ。
helloディレクトリ配下でgo runして動かしてみる。
PS C:\Users\ryouta\Desktop\go\hello> go run .
Hi, Gladys. Welcome!
#チュートリアル:エラーを返して処理する(Return and handle an error)
エラーを返して処理する
エラーを返却したときの動きを確認する。
上記で作ったgreetings.goに以下のようにする。
package greetings
import(
"errors" //追加
"fmt"
)
// Helloは、指定された人の挨拶を返します。
func Hello(name string) (string, error) { //修正
if name == "" { //追加
return "", errors.New("empty name") //追加
} //追加
//メッセージに名前を埋め込む挨拶を返します。
message := fmt.Sprintf("Hi, %v. Welcome!", name)
return message, nil //編集
}
・errorsを読み込み。
・返り値にerrorを追加。
・if文でnameが空の時は空文字とエラーの何かを返す。
→ goは複数の値を返却可能。ただし返却箇所が複数ある場合は返り値の個数は統一する必要がある。
・nilを追加
→ 返り値の二つ目でエラーがないことを表現している。つまりnilなら処理成功ということ。
次にHello.goを修正していく。
package main
import (
"fmt"
"example.com/greetings"
"log"
)
func main() {
// ログ出力の準備
// ログのプレフィックスを設定
log.SetPrefix("greetings: ")
// ログの全設定(フラグ)を一括オフにして日付情報など出さないようにする。
log.SetFlags(0)
// greetings.Helloメソッド呼び出し
message, err := greetings.Hello("")
// エラーの場合はコンソールに出力して処理終了
if err != nil {
//log.fatal()と記載すると処理終了。
log.Fatal(err)
}
// 正常の場合は、返り値をコンソールに出力
fmt.Println(message)
}
実行すると想定通りエラーが発生する。
PS C:\Users\ryouta\Desktop\go\hello> go run .
greetings: empty name
exit status 1
引数のnameに値を入れてやるとエラーが発生せずに動く。
// message, err := greetings.Hello("ルフィ")に変更
PS C:\Users\ryouta\Desktop\go\hello> go run .
Hi, ルフィ. Welcome!
#チュートリアル:ランダムな挨拶を返す(Return a random greeting)
ランダムな挨拶を返す
配列のような複数の値を持てるスライスという型があって、とても便利なので使い方を学んでいく。
greetings.goに以下を記載する。
もろもろの説明はコメントに記載。
package greetings
import(
"errors"
"fmt"
"math/rand" //乱数の生成のため
"time"
)
func Hello(name string) (string, error) {
if name == "" {
return "", errors.New("empty name")
}
//メッセージに名前を埋め込む挨拶を返します。randomFormatを呼ぶ。
message := fmt.Sprintf(randomFormat(), name)
return message, nil
}
// initメソッドはプログラム実行時に自動実行される。
func init() {
// Seedメソッドで初期化する。
// time.Now().UnixNano()を設定することで、毎回違う値が出力されるようになる。
// Seedメソッドを実行しないと毎回同じ値になるので注意。
rand.Seed(time.Now().UnixNano())
}
// メソッド名が小文字から始まると外部から呼べない内部専用メソッドとなる。
func randomFormat() string {
// スライスの生成
formats := []string{
"Hi, %v. Welcome!",
"Great to see you, %v!",
"Hail, %v! Well met!",
}
// Intn()は引数の範囲でランダムな値を返却する
return formats[rand.Intn(len(formats))]
}
hello.goは以下のように記載する。
package main
import (
"fmt"
"example.com/greetings"
"log"
)
func main() {
log.SetPrefix("greetings: ")
log.SetFlags(0)
// greetings.Helloメソッド呼び出し
message, err := greetings.Hello("Gladys") //ここだけ修正
if err != nil {
log.Panic(err)
}
fmt.Println(message)
}
実行すると以下のようにランダムな値が出力される。
PS C:\Users\ryouta\Desktop\go\hello> go run .
Hi, Gladys. Welcome!
PS C:\Users\ryouta\Desktop\go\hello> go run .
Great to see you, Gladys!
PS C:\Users\ryouta\Desktop\go\hello> go run .
Hail, Gladys! Well met!
#チュートリアル:複数の人に挨拶を返す(Return greetings for multiple people)
複数の人に挨拶を返す
for文の書き方、mapの使い方、引数がスライスの書き方を学んでいく。
具体的にはHellosという関数を作り、複数の人から挨拶された際の挙動をかいていく。
package greetings
...省略...
// Hellosメソッドを追加
// namesは挨拶してきた人の名前が設定されている
// 返り値をmapで返す
func Hellos(names []string) (map[string]string, error) {
// map生成
messages := make(map[string]string)
// 拡張for文
// 構文
// for [index(_で省略可)], [変数] := range スライス変数{}
for _, name := range names {
message, err := Hello(name)
if err != nil {
return nil, err
}
// 挨拶してきた人の名前をキーにvalueに挨拶をセット。
messages[name] = message
}
return messages, nil
}
...省略...
次にhello.goを以下のようにかいていく。
package main
import (
"fmt"
"example.com/greetings"
"log"
)
func main() {
log.SetPrefix("greetings: ")
log.SetFlags(0)
// スライスで名前をセット。
names := []string{"Gladys", "Samantha", "Darrin"} //追加
// greetings.Helloメソッド呼び出し
message, err := greetings.Hellos(names) //hello→hellosへ修正
if err != nil {
log.Panic(err)
}
fmt.Println(message)
}
実行する。
PS C:\Users\ryouta\Desktop\go\hello> go run .
map[Darrin:Hail, Darrin! Well met! Gladys:Hail, Gladys! Well met! Samantha:Great to see you, Samantha!]
#終わりに
面白かったです。