目次
Pythonでデータ解析と自動化ツールを開発しています。DjangoでのWeb開発も得意です!
Go 言語に関する基本的な事項を記載します。
モジュール、パッケージ、ライブラリ、アプリケーション
一つ以上の関数をまとめたものをパッケージとして利用します。更に一つ以上のパッケージをまとめたものをモジュールとして利用します。モジュールにはライブラリとして機能するものと、アプリケーションとして機能するものがあります。
以下の例では myapp
と mylib
モジュールの二つを作り、myapp
から mylib
を利用します。
モジュールの新規作成
ライブラリとして機能するモジュール
mkdir mylib
cd mylib
go mod init mylib
アプリケーションとして機能するモジュール
mkdir myapp
cd myapp
go mod init myapp
以下のようなファイルが作成されます。
$ cat go.mod
module mylib
go 1.15
ライブラリとして機能するモジュール内に二つのパッケージを作成
mylib
ディレクトリに以下のような二つのパッケージを作成してみます。パッケージ名はモジュール名と一致している必要はありません。また、ファイル名はパッケージ名と一致している必要はありません。同じパッケージのソースコードは同じディレクトリに存在している必要があります。
mylib/mylib.go
package mylib
import "fmt"
func Hello() {
fmt.Println("hello from mylib")
}
mylib/bbb.go
package mylib
import "fmt"
func Hello2() {
fmt.Println("hello2 from mylib")
}
mylib/aaa/aaa.go
package aaa
import "fmt"
func Hello() {
fmt.Println("hello from aaa")
}
mylib/aaa/bbb.go
package aaa
import "fmt"
func Hello2() {
fmt.Println("hello2 from aaa")
}
アプリケーションとして機能するモジュールに main パッケージを作成
エントリポイントとなるパッケージは main
とする必要があります。
myapp/myapp.go
package main
import (
"mylib"
"mylib/aaa"
)
func main() {
mylib.Hello()
mylib.Hello2()
aaa.Hello()
aaa.Hello2()
}
mylib
モジュールを import
するために、ここでは go.mod
を以下のように書き換えます。
myapp/go.mod
module myapp
go 1.15
replace mylib => ../mylib
ビルド
スクリプト言語のように実行する場合
go run myapp.go
hello from mylib
hello2 from mylib
hello from aaa
hello2 from aaa
ビルドして実行する場合
go build
cp myapp /tmp/
cd /tmp/
./myapp
hello from mylib
hello2 from mylib
hello from aaa
hello2 from aaa
いずれの場合も、初回実行時は mylib
のチェックサムが go.mod
に追記されます。
go: found mylib in mylib v0.0.0-00010101000000-000000000000
go: found mylib/aaa in mylib v0.0.0-00010101000000-000000000000
myapp/go.mod
module myapp
go 1.15
replace mylib => ../mylib
require mylib v0.0.0-00010101000000-000000000000
変数、fmt
var a, b int
a, b = 1, 2
初期値を指定する場合は以下のようにします。
var a, b int = 1, 2
初期値が存在する場合は型は省略可能です。Scala 等の他の言語のように型推論が行われます。
var a, b = 1, 2
fmt.Println(reflect.TypeOf(a)) //=> int
func
内であれば var
は :=
記法で省略できます。
a, b := 1, 2
初期化されていない変数の初期値は以下のようになります。
- 数値 → 0
- 真偽値 → false
- 文字列 → ""
型のキャストは以下のようにします。
i := 123
f := float64(i)
定数は const
で宣言します。
const Pi = 3.14
関数
func MyFunc(myarg string) string {
mystr := fmt.Sprintf("Hi, %v", myarg)
return mystr
}
fmt.Println(MyFunc("myarg")) //=> Hi, myarg
なお、大文字で始まる変数および関数はパッケージの外からでも利用できます。
同じ型の引数については、型をまとめて記載できます。また、返り値に名前を付けておくことで return
する変数を指定できます。ただし、これは長い関数については可読性を落とす可能性があります。
package main
import (
"fmt"
)
func MyFunc(x, y string) (a, b string) {
a = y
b = x
return
}
func main() {
fmt.Println(MyFunc("aaa", "bbb")) //=> bbb aaa
}
関数を引数にする関数
package main
import (
"fmt"
)
func MyFunc(fn func(string) string) {
fmt.Println(fn("aaa"))
}
func main() {
fn := func(str string) string {
return str + "!"
}
MyFunc(fn) //=> aaa!
}
クロージャ
package main
import (
"fmt"
)
func MyFunc() func() int {
cnt := 0
return func() int {
cnt++
return cnt
}
}
func main() {
fn := MyFunc()
fmt.Println(fn()) //=> 1
fmt.Println(fn()) //=> 2
fmt.Println(fn()) //=> 3
}
ログ、エラー
package main
import (
"fmt"
"errors"
"log"
)
func MyFunc(myarg string) (string, error) {
if myarg == "" {
return "", errors.New("myarg is empty")
}
return "ok", nil
}
func main() {
res, err := MyFunc("")
if err != nil {
log.Fatal(err)
}
fmt.Println(res)
}
実行例
$ go run myapp.go
2020/09/09 21:53:33 myarg is empty
exit status 1
$ echo $?
1
乱数、時間、可変長配列 (スライス)
init()
関数は、プログラム開始されてグローバル変数が初期化された後に、自動的に実行されます。
package main
import (
"fmt"
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func main() {
myslice := []string{
"aaa",
"bbb",
"ccc",
}
fmt.Println(myslice[rand.Intn(len(myslice))])
}
マップ
package main
import (
"fmt"
)
func MyFunc(myargs []string) map[string]string {
mymap := make(map[string]string)
for _, myarg := range myargs {
mymap[myarg] = myarg + "!"
}
return mymap
}
func main() {
myslice := []string{
"aaa",
"bbb",
"ccc",
}
mymap := MyFunc(myslice)
fmt.Println(mymap["aaa"]) //=> aaa!
}
for ループにおけるインデックスが不要な場合は、上記のように _
を利用します。
要素の削除
m := make(map[string]int)
m["a"] = 123
delete(m, "a")
要素の存在確認
elem, ok := m["a"]
テスト、正規表現
mylib/mylib.go
package mylib
import "fmt"
func Hello(myarg string) string {
return fmt.Sprintf("hello %v !", myarg)
}
mylib/mylib_test.go
package mylib
import (
"testing"
"regexp"
)
func TestHello1(t *testing.T) {
myarg := "aaa"
want := regexp.MustCompile(`\b` + myarg + `\b`)
res := Hello(myarg)
if !want.MatchString(res) {
t.Fatalf(`Hello(%q) = %q, want match for %#q`, myarg, res, want)
}
}
実行例
$ ls -l
drwxr-xr-x 2 myuser myuser 4096 2020-09-08 23:06 aaa
-rw-r--r-- 1 myuser myuser 81 2020-09-08 23:06 bbb.go
-rw-r--r-- 1 myuser myuser 22 2020-09-08 22:10 go.mod
-rw-r--r-- 1 myuser myuser 106 2020-09-09 22:38 mylib.go
-rw-r--r-- 1 myuser myuser 273 2020-09-09 22:39 mylib_test.go
$ go test
PASS
ok
記事の執筆者にステッカーを贈る
有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。
さらに詳しく →Feedbacks
ログインするとコメントを投稿できます。