- 5/2 から Golang を書き始めた
- つまづいて、調べて解決した点をメモっていく
- 言語学習の過程が記録として残る
- 間違っている可能性が大いにあるので、この記事は自分向けです
REPL 的なものはないの
gore なるものがあるようだ
インストール方法
$ go get -u github.com/motemen/gore/cmd/gore
$ go get -u github.com/mdempsky/gocode # for code completion
$ go get -u github.com/k0kubun/pp # or github.com/davecgh/go-spew/spew
$
$ gore
依存モジュール管理ツール
Godeps なるものがあるらしい
$ go get github.com/tools/godep
go のバージョン管理システム
goenv なるものがあるらしい
$ brew install goenv
$ goenv install -l
Available versions:
1.2.2
1.3.0
1.3.1
1.3.2
1.3.3
...
$ echo 'eval "$(goenv init -)"' >> ~/.bash_profile
$ echo 'export GOPATH=$HOME/go' >> ~/.bash_profile
$ echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.bash_profile
$ source ~/.bash_profile
$
$ goenv install 1.11.4
...
$ goenv rehash
$ goenv global 1.11.4
$ go version
go version go1.11.4 darwin/amd64
string? みたいなのを実現したい
- optional なフィールドをどう表現するのという話
- どうやら以下のようにやっていく模様?
type Input struct {
name string
age *int
}
func main() {
age := 10
i1 := Input{"John", &age}
fmt.Println(i1) //=> {John 0xc000083458}
i2 := Input{"Jack", nil}
fmt.Println(i2) //=> {Jack <nil>}
}
ISO8601 の日付 string を取得したい
func main() {
now := time.Now().Format(time.RFC3339)
fmt.Println(now) //=> 2019-05-02T15:42:15Z
}
時刻の足し算・引き算
gore> :import time
gore> now := time.Now()
2019-05-03 01:27:30 Local
gore> now.Add(time.Hour)
2019-05-03 02:27:49 Local
gore> now.Add(24 * time.Hour)
2019-05-04 01:28:42 Local
string2int, int2string
gore> strconv.Atoi("1")
1
nil
gore> strconv.Atoi("hoge")
0
&strconv.NumError{
Func: "Atoi",
Num: "hoge",
Err: &errors.errorString{
s: "invalid syntax",
},
}
gore> strconv.Itoa(2)
"2"
変数・定数定義のシンタックス
gore> var i int = 1
1
gore> var j = 2
2
gore> k := 3
3
# 変数宣言時に値はゼロ初期化されている
gore> var s string
gore> s
""
gore> var i int64
gore> i
0
# 定数
gore> var hoge = 1
1
gore> hoge = 2
2
gore> const fuga = 3
3
gore> fuga = 4
cannot assign to fuga
ポインタと参照まわり
a := 1
var pa *int
pa = &a
fmt.Println(pa) //=> <addr01>
fmt.Println(*pa) //=> 1
ppa := &pa
fmt.Println(**ppa) //=> 1
関数に値を渡したときのふるまい
package main
import "fmt"
type dog struct {
name string
}
func main() {
john := dog{name: "john"}
fmt.Printf("%p\n", &john) //=> addr01
michel := rename(john, "michel")
fmt.Printf("%p\n", &john) //=> addr01
fmt.Printf("%p\n", &michel) //=> addr03
}
func rename(d dog, newName string) (ret dog) {
fmt.Printf("%p\n", &d) //=> addr02 (copied)
d.name = newName
return d
}
スコープ
変数・定数・関数に対して統一的に以下のとおり
- キャメルケース: パッケージスコープ
- パスカルケース: パブリック
関数の定義
gore> func add(x int, y int) int {
..... return x + y
..... }
gore>
gore> add(1, 2)
3
gore> func calc(x int, y int) (add int, sub int, mul int) {
..... return x + y, x - y, x * y
..... }
gore> i, j, k := calc(2, 3)
5
-1
6
gore> i
5
gore> j
-1
gore> k
6
// こんな記述もできる
gore> func calc(x int, y int) (hoge int, fuga int, piyo int) {
hoge = x + y
fuga = x - y
piyo = x * y
return
gore> calc(1, 2)
3
-1
2
Goroutine のさわり
package main
import (
"fmt"
"runtime"
"time"
)
func heavyProcessA() {
fmt.Println("A: work hard!!")
time.Sleep(time.Second)
fmt.Println("A: finished work!!")
}
func heavyProcessB() {
fmt.Println("B: work hard!!")
time.Sleep(500 * time.Millisecond)
fmt.Println("B: finished work!!")
}
func main() {
go heavyProcessA()
go heavyProcessB()
fmt.Println("task scheduled: A, B")
for runtime.NumGoroutine() != 1 {
}
fmt.Println("Exit 0")
}
/*
task scheduled: A, B
B: work hard!!
A: work hard!!
B: finished work!!
A: finished work!!
Exit 0
*/
channel
- 値がくるまで待つ
- async/await 的なものを Golang で実現する方法
package main
import (
"fmt"
"time"
)
func calcOnePlusOne(result chan int) {
fmt.Println("1+1: thinking...")
time.Sleep(time.Second)
fmt.Println("1+1=2")
result <- 1
}
func calcOnePlusTwo(result chan int) {
fmt.Println("1+2: thinking...")
time.Sleep(500 * time.Millisecond)
fmt.Println("1+2=3")
result <- 3
}
func main() {
onePlusOne := make(chan int)
onePlusTwo := make(chan int)
go calcOnePlusOne(onePlusOne)
go calcOnePlusTwo(onePlusTwo)
fmt.Println("task scheduled")
res := <-onePlusOne + <-onePlusTwo
fmt.Println(res)
fmt.Println("finished")
}
/*
task scheduled
1+2: thinking...
1+1: thinking...
1+2=3
1+1=2
4
finished
*/
C# に翻訳すると以下のようなものと同じようなふるまいに見える
onePlusOne = await CalcOnePlusOne();
onePlusTwo = await CalcOnePlusTwo();
var res = onePlusOne + onePlusTwo
三項演算子ないの
var str = cond ? “hoge” : null;
var s *string
if cond {
t := "hogefuga"
s = &t
}
int の最大値
gore> math.MaxInt64
9223372036854775807
MD5
gore> :import "crypto/md5"
gore> md5.Sum([]byte("hoge"))
[16]uint8{
0xea, 0x70, 0x3e, 0x7a, 0xa1, 0xef, 0xda, 0x00, 0x64, 0xea, 0xa5, 0x07, 0xd9, 0xe8, 0xab, 0x7e,
}
構造体にメソッドを定義する
type user struct {
name string
}
func (u user) sayHello() string {
return "Hello! My name is " + u.name
}
// a-zA-Z0-9
func main() {
u := user{"john"}
fmt.Println(u.sayHello())
}
メソッド呼び出しと簡略系
メソッド呼び出しx.m()は、x(の型)のメソッド群がmを含んでいて、かつ引数リストがmの引数リストに代入可能なときに有効となります。またxがアドレス指定可能であり、&xのメソッド群がmを含んでいるならば、x.m()は、(&x).m()の簡略形として使用可能です。
type Animal struct {
name string
}
func (a *Animal) Greet(yourName string) string {
return fmt.Sprintf("Hello, {0}. My name is {1}", yourName, (*a).name)
}
a := Animal{name: "John"}
a.Greet("Ken") //=> (&a).Greet("Ken") とコンパイラが解釈する
(&a).Greet("Ken") //=> 定義通り呼び出せる