Golangのbuffered channel
を使ってLockすることができる。 buffered channel
のサイズを1に指定して、複数のgoroutinesの間で同期する
package main
import (
"fmt"
"time"
)
func main() {
lock := make(chan bool, 1) // サイズ1のbuffered channelを作る
for i := 1; i < 7; i++ {
go worker(i, lock)
}
time.Sleep(10 * time.Second)
}
func worker(id int, lock chan bool) {
fmt.Printf("%d wants the lock\n", id)
lock <- true // lockを所得しようとする
fmt.Printf("%d has the lock\n", id)
time.Sleep(500 * time.Millisecond)
fmt.Printf("%d is releasing the lock\n", id)
<-lock // lockから値を取り出して、lockをrelease
}
main関数に作られている6個のgoroutineは同時にそれぞれ値true
を lock
という名前のbuffered channel
に送って、同時にlocker
を取得しようとしているが、lock
がサイズが1なので、2個目のwokerがメッセージを送ろうとしても、ブロックされる。1個目workerがlock
から値を取り出して、lock
をreleaseしてから、二個目のworkerが初めてlock
にメッセージを送ることができる。
$ go run play47.go
2 wants the lock
1 wants the lock
5 wants the lock
2 has the lock
4 wants the lock
3 wants the lock
6 wants the lock
2 is releasing the lock
1 has the lock
1 is releasing the lock
4 has the lock
4 is releasing the lock
5 has the lock
5 is releasing the lock
3 has the lock
3 is releasing the lock
6 has the lock
6 is releasing the lock
テストコードがどのぐらいカバーしているかを教えてくれる
$ go test -cover
go buildのヘルプ
go build --help
Spacemacsのgo-modeのショートカット
, i r
- go-remove-unused-imports 不要なimportを削除
, h h
- godoc-at-point 関数のドキュメントをみる
, t p
- go-run-package-tests パッケージのテストを実行
Golangの database/sql
の話
if you fail to release connections back to the pool, you can cause db.SQL to open a lot of connections
The sql.DB
performs some important tasks for you behind the scenes:
- It opens and closes connections to the actual underlying database, via the driver.
- It manages a pool of connections as needed, which may be a variety of things as mentioned.
To create a sql.DB
, you use sql.Open()
. This returns a *sql.DB
It is idiomatic to defer db.Close()
if the sql.DB
should not have a lifetime beyond the scope of the function.
sql.Open()
does not establish any connections to the database, nor does it validate driver connection parameters. Instead, it simply prepares the database abstraction for later use.
Under the hood, db.Query()
actually prepares, executes, and closes a prepared statement. That’s three round-trips to the database.
If a query returns at most one row, you can use a shortcut around some of the lengthy boilerplate code:
var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
You can also call QueryRow()
on a prepared statement:
stmt, err := db.Prepare("select name from users where id = ?")
if err != nil {
log.Fatal(err)
}
var name string
err = stmt.QueryRow(1).Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
Consider the following code:
for rows.Next() {
// ...
}
if err = rows.Err(); err != nil {
// handle the error here
}
The error from rows.Err()
could be the result of a variety of errors in the rows.Next()
loop. The loop might exit for some reason other than finishing the loop normally, so you always need to check whether the loop terminated normally or not. An abnormal termination automatically calls rows.Close()
Consider the following code to fetch a single row:
var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
log.Fatal(err)
}
fmt.Println(name)
What if there was no user with id = 1
? Then there would be no row in the result, and .Scan()
would not scan a value into name. Go defines a special error constant, called sql.ErrNoRows
, which is returned from QueryRow()
when the result is empty.
The above code is better written like this instead:
var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
if err == sql.ErrNoRows {
// there were no rows, but otherwise no error occurred
} else {
log.Fatal(err)
}
}
fmt.Println(name)
You should only run into this error when you’re using QueryRow()
. If you encounter this error elsewhere, you’re doing something wrong.
Identifying specific database errors:
It can be tempting to write code like the following:
rows, err := db.Query("SELECT someval FROM sometable")
// err contains:
// ERROR 1045 (28000): Access denied for user 'foo'@'::1' (using password: NO)
if strings.Contains(err.Error(), "Access denied") {
// Handle the permission-denied error
}
In the MySQL driver that this tutorial focuses on, you could write the following code:
if driverErr, ok := err.(*mysql.MySQLError); ok { // Now the error number is accessible directly
if driverErr.Number == 1045 {
// Handle the permission-denied error
}
}
or
if driverErr, ok := err.(*mysql.MySQLError); ok {
if driverErr.Number == mysqlerr.ER_ACCESS_DENIED_ERROR {
// Handle the permission-denied error
}
}
What if your connection to the database is dropped, killed, or has an error?
You don’t need to implement any logic to retry failed statements when this happens. As part of the connection pooling in database/sql, handling failed connections is built-in.
You begin a transaction with a call to db.Begin(), and close it with a Commit() or Rollback() method on the resulting Tx variable. Under the covers, the Tx gets a connection from the pool, and reserves it for use only with that transaction.
You should not mingle the use of transaction-related functions such as Begin()
and Commit()
with SQL statements such as BEGIN
and COMMIT
in your SQL code. Bad things happen.
下のソースは エラーを出す。つまり直接別のパッケージの中のタイプを拡張することはできない。
cannot define new methods on non-local type int
package main
func (i int) Add(j int) int {
return i + j
}
func main() {}
もし既存のタイプを拡張したい場合 aliasを定義いて、拡張する
package main
import "fmt"
type myInt int
// you can't extend existing types(int) in another package.
// 既存のintに対して, 拡張してAddというメソッドを追加する
func (i myInt) Add(j myInt) myInt {
return i + j
}
func main() {
i := myInt(5)
j := myInt(6)
fmt.Println(i.Add(j))
fmt.Println(i.Add(j) + 12)
}
Centos 7にGolangをインストール(install)
wget https://storage.googleapis.com/golang/go1.10.3.linux-amd64.tar.gz
sudo tar -C /usr/local -xvzf go1.10.3.linux-amd64.tar.gz
cat /etc/profile.d/path.sh
export PATH=$PATH:/usr/local/go/bin
cat ~/.bash_profile
...
export GOBIN="$HOME/go-projects/bin"
export GOPATH="$HOME/go-projects/src"
...
mkdir -p $HOME/go-projects/bin $HOME/go-projects/src
source /etc/profile && source ~/.bash_profile
ローカルのMACからCentos用にGo ファイルをCross Compile
$ GOOS=linux GOARCH=amd64 go build play1.go
Passwordをbcrypt
でハッシュした後にbase64
でencodeする
package main
import (
"encoding/base64"
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
password := []byte("MyPassword")
// Hashing the password with the default cost of 10
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
if err != nil {
panic(err)
}
// fmt.Println(hashedPassword)
s := base64.StdEncoding.EncodeToString(hashedPassword)
fmt.Println(s)
t, _ := base64.StdEncoding.DecodeString(s)
// Comparing the password with the hash
err = bcrypt.CompareHashAndPassword(t, password)
fmt.Println(err) // nil means it is a match
}
const iota
package main
import (
"fmt"
)
const (
CategoryBooks = iota // 0
CategoryHealth // 1
CategoryClothing // 2
)
func main() {
fmt.Println(CategoryBooks) // 0
}
init()
function Golang.
AnswerToLife()
is guaranteed to run before init()
is called, and init()
is guaranteed to run before main()
is called.
Keep in mind that init()
is always called, regardless if there's main
or not, so if you import a package that has an init
function, it will be executed.
var WhatIsThe = AnswerToLife()
func AnswerToLife() int {
return 42
}
func init() {
WhatIsThe = 0
}
func main() {
if WhatIsThe == 0 {
fmt.Println("It's all a lie.")
}
}
$ go run play.go
It's all a lie.
かんたんなtcp server
server.go
package main
import (
"bufio"
"fmt"
"net"
"strings"
)
func main() {
fmt.Println("Launching server...")
ln, _ := net.Listen("tcp", ":8081")
conn, _ := ln.Accept()
for {
// func NewReader(rd io.Reader) *Reader
// func (b *Reader) ReadString(delim byte) (string, error)
// type Reader struct {}
message, _ := bufio.NewReader(conn).ReadString('\n')
fmt.Print("Message Received:", string(message))
new_message := strings.ToUpper(message)
conn.Write([]byte(new_message + "\n"))
}
}
client.go
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
conn, _ := net.Dial("tcp", "127.0.0.1:8081")
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Text to send: ")
text, _ := reader.ReadString('\n')
fmt.Fprintf(conn, text+"\n")
message, _ := bufio.NewReader(conn).ReadString('\n')
fmt.Print("Message from server:" + message)
}
}
json.NewEncoder
の一例
package main
import "fmt"
import "bytes"
import "net/http"
import "encoding/json"
import "io"
import "os"
import "io/ioutil"
type User struct {
Id string
Balance uint64
}
func main() {
u := User{Id: "US123", Balance: 8}
b := new(bytes.Buffer)
// func NewEncoder(w io.Writer) *Encoder
// NewEncoder returns a new encoder that writes to w.
// func (enc *Encoder) Encode(v interface{}) error
// Encode writes the JSON encoding of v to the stream, followed by a newline character.
json.NewEncoder(b).Encode(u)
res, _ := http.Post("https://httpbin.org/post", "application/json; charset=utf-8", b)
// func Copy(dst Writer, src Reader) (written int64, err error)
// Copy copies from src to dst until either EOF is reached on src or an error occurs.
// It returns the number of bytes copied and the first error encountered while copying, if any.
io.Copy(os.Stdout, res.Body) // Stdoutに出力される
}
PostForm
issues a POST to the specified URL, with data's keys and values URL-encoded as the request body.
package main
import (
"io/ioutil"
"net/http"
"net/url"
)
func main() {
// func PostForm(url string, data url.Values) (resp *Response, err error)
resp, _ := http.PostForm(
"http://httpbin.org/post",
url.Values{"foo": {"bar", "key"}},
)
body, _ := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
println(string(body))
}
実行結果
$ go run play5.go
{
"args": {},
"data": "",
"files": {},
"form": {
"foo": [
"bar",
"key"
]
},
"headers": {
"Accept-Encoding": "gzip",
"Content-Length": "15",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "Go-http-client/1.1"
},
"json": null,
"origin": "210.168.36.157",
"url": "http://httpbin.org/post"
}
Mapのキー削除にdelete
を使う
package main
import (
"fmt"
)
func main() {
commits := map[string]int{
"rsc": 3711,
"r": 2138,
"gri": 1908,
"adg": 912,
}
fmt.Println(commits)
delete(commits, "rsc")
fmt.Println(commits)
}
Reflection in computing is the ability of a program to examine its own structure, particularly through types; it's a form of metaprogramming.
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
v := reflect.ValueOf(x)
fmt.Println(v) // 3.4
fmt.Println(v.Float())
fmt.Println(v.Type()) // float64
fmt.Println(v.Kind()) // float64
fmt.Println(v.Kind() == reflect.Float64) // true
fmt.Println(reflect.TypeOf(v)) // reflect.Value
fmt.Println(v.CanSet()) // false
fmt.Println(v.Int()) // panic: reflect: call of reflect.Value.Int on float64 Value
}
func ReadFull(r Reader, buf []byte) (n int, err error)
ReadFull reads exactly len(buf)
bytes from r
into buf
. It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF
only if no bytes were read. If an EOF
happens after reading some but not all the bytes, ReadFull returns ErrUnexpectedEOF
. On return, n == len(buf) if and only if err == nil.
package main
import (
"fmt"
"io"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
buf := make([]byte, 4)
if _, err := io.ReadFull(r, buf); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf) // some
// minimal read size bigger than io.Reader stream
longBuf := make([]byte, 64)
if _, err := io.ReadFull(r, longBuf); err != nil {
fmt.Println("error:", err) // error: unexpected EOF
}
}
I frequently see code where byte slices or strings are written to a bytes.Buffer
and then the buffer is used as a reader:
var buf bytes.Buffer
buf.WriteString("foo")
http.Post("http://example.com/", "text/plain", &buf)
However, this approach incurs heap allocations
which will be slow and use additional memory. A better option is to use the strings.Reader
:
r := strings.NewReader("foobar")
http.Post("http://example.com", "text/plain", r)
A type assertion provides access to an interface value's underlying concrete value.
t := i.(T)
This statement asserts that the interface value i
holds the concrete type T
and assigns the underlying T
value to the variable t
.
If i
does not hold a T
, the statement will trigger a panic.
To test whether an interface value holds a specific type, a type assertion can return two values: the underlying value and a boolean value that reports whether the assertion succeeded.
t, ok := i.(T)
If i
holds a T
, then t
will be the underlying value and ok
will be true
.
If not, ok
will be false and t
will be the zero value of type T
, and no panic occurs.
Note the similarity between this syntax and that of reading from a map.
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s) // hello
s, ok := i.(string)
fmt.Println(s, ok) // hello true
f, ok := i.(float64)
fmt.Println(f, ok) // 0, false
f = i.(float64)
fmt.Println(f) // panic: interface conversion: interface is string, not float64
}
Go is statically typed. Every variable has a static type, that is, exactly one type known and fixed at compile time: int
, float32
, *MyType
, []byte
, and so on. If we declare
type MyInt int
var i int
var j MyInt
then i has type int and j has type MyInt. The variables i and j have distinct static types and, although they have the same underlying type, they cannot be assigned to one another without a conversion.
var r io.Reader
r = os.Stdin
r = bufio.NewReader(r)
r = new(bytes.Buffer)
// and so on
It's important to be clear that whatever concrete value r may hold, r
's type is always io.Reader: Go is statically typed and the static type of r is io.Reader.
Higher order functions filter
package main
import "fmt"
type predicate func(int) bool
func main() {
fmt.Println(filter([]int{1, 2, 3, 4, 5, 6}, func(x int) bool {
return x%2 == 0
}))
}
func filter(arr []int, f predicate) []int {
result := []int{}
for _, value := range arr {
if f(value) {
result = append(result, value)
}
}
return result
}
Golangの smartystreets/go-aws-auth 軽量認証パッケージを使ってS3のバケット一覧リストをとってくる.
package main
import (
"fmt"
"github.com/smartystreets/go-aws-auth"
"net/http"
"io/ioutil"
)
func main() {
client := new(http.Client)
req, err := http.NewRequest("GET", "https://s3.amazonaws.com/", nil)
awsauth.Sign(req, awsauth.Credentials{
AccessKeyID: "*******************",
SecretAccessKey: "*******************",
})
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
}
labstack/echo
sample
package main
import (
"github.com/labstack/echo"
"github.com/labstack/echo/engine/standard"
"net/http"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
// String sends a string response with status code.
return c.String(http.StatusOK, "Hello world")
})
// standard.New returns `Server` instance with provided listen address.
e.Run(standard.New(":1323"))
}
base32
package main
import (
"fmt"
"encoding/base32"
)
func main() {
shared_secret := "ABCDEFGAAAAAAAAAA"
secret := base32.StdEncoding.EncodeToString([]byte(shared_secret))
fmt.Println(secret) // IFBEGRCFIZDUCQKBIFAUCQKBIFAQ====
secretBytes, err := base32.StdEncoding.DecodeString(secret)
if err != nil {
panic(err)
}
fmt.Println(secretBytes) // [65 66 67 68 69 70 71 65 65 65 65 65 65 65 65 65 65]
}
3桁でintを表示する
package main
import "fmt"
type Digits int
func (d Digits) Format(in int32) string {
f := fmt.Sprintf("%%0%dd", d)
return fmt.Sprintf(f, in)
}
func main() {
fmt.Println(Digits(3).Format(21)) // 021
}
Print out a integer in binary format
package main
import (
// "encoding/binary"
"fmt"
"strconv"
)
func main() {
var i int64 = 4
fmt.Println(strconv.FormatInt(i, 2))
}
Tod define methods on a type you don't "own", you need to define an alias for the type you want to extend
package main
import (
"fmt"
"strings"
)
type MyStr string
type MyFloat float64
func (s MyStr) Uppercase() string {
return strings.ToUpper(string(s))
}
func (f MyFloat) Abs() float64 {
if f < 0 {
return -float64(f)
} else {
return float64(f)
}
}
func main() {
fmt.Println(MyStr("test").Uppercase())
fmt.Println(MyFloat(-3.45).Abs())
}
A message authentication code (MAC) is produced from a message and a secret key by a MAC algorithm. An important property of a MAC is that it is impossible¹ to produce the MAC of a message and a secret key without knowing the secret key.
An HMAC is a MAC which is based on a hash function. The basic idea is to concatenate the key and the message, and hash them together.
メッセージをキーを使って暗号化する。
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
)
func ComputeHmac256(message string, secret string) string {
key := []byte(secret)
h := hmac.New(sha256.New, key)
h.Write([]byte(message))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
func main() {
fmt.Println(ComputeHmac256("Message", "secret"))
}
url.Value
package main
import (
"fmt"
"net/url"
)
func main() {
// type Values map[string][]string
// It is typically used for query parameters and form values.
v := url.Values{}
// Set sets the key to value. It replaces any existing values.
v.Set("name", "Ava")
// Add adds the value to key. It appends to any existing values associated with key.
v.Add("name", "Mike")
v.Add("friend", "Jess")
v.Add("friend", "Sarah")
v.Add("friend", "Zoe")
fmt.Println(v.Encode()) // friend=Jess&friend=Sarah&friend=Zoe&name=Ava
fmt.Println(v.Get("name")) // Ava
fmt.Println(v["name"]) // [Ava Mike]
fmt.Println(v.Get("friend")) // Jess
fmt.Println(v["friend"]) // [Jess Sarah Zoe]
}
strings.Replace
package main
import (
"fmt"
"strings"
)
func main() {
// func Replace(s, old, new string, n int) string
// 二回replace
fmt.Println(strings.Replace("oink oink oink", "k", "ky", 2)) // oinky oinky oink
// replace回数無制限 -1 < 0 だから
fmt.Println(strings.Replace("oink oink oink", "oink", "moo", -1)) // moo moo moo
}
Create a Golang map of Lists, a slice
was the right choice
package main
import (
"fmt"
)
func main() {
x := make(map[string][]string)
x["key1"] = append(x["key1"], "value1.1")
x["key1"] = append(x["key1"], "value1.2")
x["key2"] = append(x["key2"], "value2.1")
x["key2"] = append(x["key2"], "value2.2")
fmt.Println(x["key1"][0]) // value1.1
fmt.Println(x["key1"][1]) // value1.2
fmt.Println(x) // map[key1:[value1.1 value1.2] key2:[value2.1 value2.2]]
}
日本時間だとUTC()
つけると9時間の差
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now()) // 2016-10-07 14:31:41.77854884 +0900 JST
fmt.Println(time.Now().UTC()) // 2016-10-07 05:31:41.778682477 +0000 UTC
}
sha256で文字列をHASH
package main
import (
"crypto/sha256"
"fmt"
)
func main() {
str := ""
h := sha256.New()
h.Write([]byte(str))
fmt.Printf("SHA-256: %x\n", h.Sum(nil))
}
godefをインストールいて、spacemacsの中で , g g
で関数定義にJump
go get -u -v github.com/rogpeppe/godef
timeパッケージの操作
package main
import (
"fmt"
"time"
)
func main() {
p := fmt.Println
now := time.Now()
p(now) // 2016-10-06 13:39:49.999004018 +0900 JST
then := time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
p(then) // 2009-11-17 20:34:58.651387237 +0000 UTC
p(then.Year()) // 2009
p(then.Month()) // November
p(then.Day()) // 17
p(then.Hour()) // 20
p(then.Minute()) // 34
p(then.Second()) // 58
p(then.Nanosecond()) // 651387237
p(then.Location()) // UTC
p(then.Weekday()) // Tuesday
p(then.Before(now)) // true
p(then.After(now)) // true
p(then.Equal(now)) // true
diff := now.Sub(then)
p(diff) // 60344h12m22.386627698s
p(diff.Hours()) // 60344.23472463381
p(diff.Minutes()) // 3.6206540834780284e+06
p(diff.Seconds()) // 2.172392450086817e+08
p(diff.Nanoseconds()) // 217239245008681719
p(then.Add(diff)) // 2016-10-06 04:50:06.40062202 +0000 UTC
p(then.Add(-diff)) // 2002-12-30 12:19:15.121767856 +0000 UTC
}
net/http
パッケージを利用して、POST操作
package main
import (
"fmt"
"io/ioutil"
"net/http"
"bytes"
"reflect"
)
func main() {
client := &http.Client{}
body := []byte("{\n \"title\": \"Buy chesse and bread for breakfast.\"\n}")
req, _ := http.NewRequest("POST", "https://private-e34066-restapi3.apiary-mock.com/notes", bytes.NewBuffer(body))
req.Header.Add("Content-Type", "application/json")
// {{
// "title": "Buy chesse and bread for breakfast."
// }}
fmt.Println(req.Body)
fmt.Println(reflect.TypeOf(req.Body)) // ioutil.nopCloser
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
}
net/http
パッケージを利用して、GET操作
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
client := &http.Client{}
req, _ := http.NewRequest("GET", "https://private-anon-f58ffd07fd-restapi3.apiary-mock.com/notes", nil)
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
resp_body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(resp.Status)
fmt.Println(string(resp_body))
}
When you create a type declaration by defining a new type from an existing (non-interface) type, you don't inherit the methods defined for that existing type.
Fails:
package main
import "sync"
type myMutex sync.Mutex
func main() {
var mtx myMutex
mtx.Lock() //error
mtx.Unlock() //error
}
//./play.go:9: mtx.Lock undefined (type myMutex has no field or method Lock)
// ./play.go:10: mtx.Unlock undefined (type myMutex has no field or method Unlock)
If you do need the methods from the original type you can define a new struct type embedding the original type as an anonymous field.
Works:
package main
import "sync"
type myMutex struct {
sync.Mutex
}
func main() {
var lock myMutex
lock.Lock()
lock.Unlock()
}
URL関連の操作
package main
import "fmt"
import "net"
import "net/url"
func main() {
s := "postgres://user:[email protected]:5432/path?k=v#f"
u, err := url.Parse(s)
if err != nil {
panic(err)
}
fmt.Println(u.Scheme) // postgres
fmt.Println(u.User) // user:pass
fmt.Println(u.User.Username()) // user
p, _ := u.User.Password()
fmt.Println(p) // pass
fmt.Println(u.Host) // host.com:5432
host, port, _ := net.SplitHostPort(u.Host)
fmt.Println(host) // host.com
fmt.Println(port) // 5432
}
Sort By Length
package main
import "fmt"
import "sort"
type ByLength []string
// We implement sort.Interface - Len, Less, Swap on our type so we
// can use the sort package's generic Sort function
func (s ByLength) Len() int {
return len(s)
}
func (s ByLength) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s ByLength) Less(i, j int) bool {
return len(s[i]) < len(s[j])
}
func main() {
fruits := []string{"peach", "banana", "kiwi"}
sort.Sort(ByLength(fruits))
fmt.Println(fruits)
}
Sort
package main
import "fmt"
import "sort"
func main() {
strs := []string{"c", "a", "b"}
sort.Strings(strs)
fmt.Println("Strings:", strs) // Strings: [a b c]
ints := []int{7, 2, 4}
sort.Ints(ints)
fmt.Println("Ints:", ints) // Ints: [2 4 7]
s := sort.IntsAreSorted(ints)
fmt.Println("Sorted:", s) // Sorted: true
}
Go allows you to define a struct that has fields but with no variable names. These fields are called anonymous fields. What happens when more than one of the composed structs or the composing struct has the same field name. If there is a field in an outer struct with the same name as a field in an inner anonymous struct, then the outer one is accessible by default.
package main
import "fmt"
type Kitchen struct {
numOfPlates int
}
type House struct {
Kitchen
numOfRooms int
}
func main() {
h := House{Kitchen{10}, 3}
fmt.Println("House has this many rooms:", h.numOfRooms)
// numOfPlates is a field of anonymous field Kitchen, so it can be referred to like a field of House
fmt.Println("House has this many plates:", h.numOfPlates)
fmt.Println("The Kitchen contents of this house are:", h.Kitchen)
}
// House has this many rooms: 3
// House has this many plates: 10
// The Kitchen contents of this house are: {10}
16進で表示している文字列をbase64が使える形のバイト列の変換して、encodeする
package main
// This syntax imports the `encoding/base64` package with
// the `b64` name instead of the default `base64`. It'll
// save us some space below.
import b64 "encoding/base64"
import "fmt"
func main() {
// Here's the `string` we'll encode/decode.
data := "abc123!?$*&()'-=@~"
// Go supports both standard and URL-compatible
// base64. Here's how to encode using the standard
// encoder. The encoder requires a `[]byte` so we
// cast our `string` to that type.
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)
// Decoding may return an error, which you can check
// if you don't already know the input to be
// well-formed.
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
fmt.Println(string(sDec))
fmt.Println()
// This encodes/decodes using a URL-compatible base64
// format.
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(uEnc)
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
fmt.Println(string(uDec))
}
Scanは\n
をスペース扱い
package main
import "fmt"
func main() {
var x, y int
fmt.Printf("Enter 2 numbers> ")
fmt.Scan(&x)
fmt.Scan(&y)
fmt.Printf("Sending %d and %d\n", x, y)
}
Sscanln is similar to Sscan, but stops scanning at a newline and after the final item there must be a newline or EOF.
package main
import "fmt"
func main() {
answers := "1 0 \n 8"
var a, b, c int
fmt.Sscanln(answers, &a, &b, &c)
// cはscanされていない
fmt.Println(a, b, c)
answers = "1 0 8"
fmt.Sscanln(answers, &a, &b, &c)
fmt.Println(a, b, c)
}
Scanf scans text read from standard input, storing successive space-separated values into successive arguments as determined by the format. It returns the number of items successfully scanned. If that is less than the number of arguments, err will report why.
package main
import "fmt"
func main() {
var num int
for i := 0; i < 3; i++ {
// It returns the number of items successfully scanned.
n, err := fmt.Scanf("%d\n", &num)
if err != nil {
panic(err) // アフファベット入力すると panic: expected integer
}
}
}
NewLine が入力されるまでScanする, スペースで入力を区切る
package main
import "fmt"
func main() {
var s1 string
var s2 string
fmt.Scanln(&s1, &s2)
fmt.Println(s1)
fmt.Println(s2)
return
}
Types with empty []
, such as []int
are actually slices, not arrays. In Go, the size of an array is part of the type
, so to actually have an array you would need to have something like [16]int
, and the pointer to that would be *[16]int
.
Unit Testは
t.Error()
でエラーを出す場合の例
package hello
import "testing"
func TestAverage(t *testing.T) {
var v float64
v = Average([]float64{1,2})
if v != 1.5 {
t.Error("Expected 1.5, got ", v)
}
}
複数のデータペアを試す場合
package hello
import "testing"
type testpair struct {
values []float64
average float64
}
var tests = []testpair{
{[]float64{1,2}, 1.5},
{[]float64{1,1,1,1}, 1},
{[]float64{-1, 1}, 0},
}
func TestAverage(t *testing.T) {
for _, pair := range tests {
v := Average(pair.values)
if v != pair.average {
t.Error(
"For", pair.values,
"expected", pair.average,
"got", v,
)
}
}
}
t.Fatalf
でもエラー表示
func TestHello(t *testing.T) {
expectedStr := "Hello, Testing!"
result := hello()
if result != expectedStr {
t.Fatalf("Expected %s, got %s", expectedStr, result)
}
}
Golang はすべてのプロジェクトを一箇所で保管する
GOPATH
を~/Playground/Goalng
に設定mkdir -p $GOPATH/src/github.com/ColdFreak/hello
touch $GOPATH/src/github.com/ColdFreak/hello/hello.go
go install github.com/ColdFreak/hello
hello.go
がbuildされて、hello
コマンドが$GOPATH/bin/
ディレクトリにインストールされる$GOPATH/bin/hello
でコマンド実行
Rate limiting, 最初の三つのリクエストが全力で処理して、4つ目からは200 msecごとに処理する
$ go run play.go
request 1 2016-09-30 08:58:32.852346175 +0900 JST
request 2 2016-09-30 08:58:32.852463183 +0900 JST
request 3 2016-09-30 08:58:32.852467413 +0900 JST
request 4 2016-09-30 08:58:33.056838052 +0900 JST
request 5 2016-09-30 08:58:33.256361329 +0900 JST
package main
import "fmt"
import "time"
func main() {
// 時間をchannelに突っ込む
burstyLimiter := make(chan time.Time, 3)
for i := 0; i < 3; i++ {
burstyLimiter <- time.Now() //
}
// 裏で動いているgoroutineが200 Millisecondで時間をchannelに突っ込む
go func() {
for t := range time.Tick(time.Millisecond * 200) {
burstyLimiter <- t
}
}()
burstyRequests := make(chan int, 5)
for i:= 1; i <= 5; i++ {
burstyRequests <- i
}
close(burstyRequests)
for req := range burstyRequests {
<- burstyLimiter
fmt.Println("request", req, time.Now())
}
}
Tick is a convenience wrapper for NewTicker providing access to the ticking channel only. 下のプログラムは1秒ごとに時間を返す
package main
import "fmt"
import "time"
func main() {
// func Tick(d Duration) <-chan Time
c := time.Tick(1 * time.Second)
for now := range c { // NewTickerのやり方と違う
fmt.Printf("%v\n", now)
}
}
時間の操作
package main
import (
"fmt"
"time"
)
func main() {
t0 := time.Now()
fmt.Printf("%v\n", t0) // 2016-09-29 15:11:32.824271554 +0900 JST
time.Sleep(time.Second * 2)
t1 := time.Now()
fmt.Printf("%v", t1.Sub(t0)) // 2.005253857s
}
RiakCSのmoss.users
バケットからRiakCSのキー一覧を取得. goroutine, channelなど一切つかなわい
package main
import(
"reflect"
"fmt"
"os"
"time"
"log"
riak "github.com/basho/riak-go-client"
)
// func New(out io.Writer, prefix string, flag int) *Logger
var slog = log.New(os.Stdout, "", log.LstdFlags)
var elog = log.New(os.Stderr, "", log.LstdFlags)
func LogErr(source string, err error) {
// func (l *Logger) Println(v ...interface{})
elog.Println("[ERROR]", source, err)
}
func ErrExit(err error) {
LogErr("ErrExit", err)
os.Exit(1)
}
func main() {
// riak.EnableDebugLogging = true
// NodeOptions is a struct
nodeOpts := &riak.NodeOptions{
RemoteAddress: "127.0.0.1:8087",
RequestTimeout: time.Second * 15,
}
// Node is a struct
var node *riak.Node
var err error
// func NewNode(options *NodeOptions) (*Node, error)
if node, err = riak.NewNode(nodeOpts); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
// pointerの配列
nodes := []*riak.Node{node}
// ClusterOptions is a struct
opts := &riak.ClusterOptions {
Nodes: nodes,
}
// func NewCluster(options *ClusterOptions) (*Cluster, error)
cluster, err := riak.NewCluster(opts)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
defer func() {
// func (c *Cluster) Stop() (err error)
if err := cluster.Stop(); err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
}()
if err = cluster.Start(); err != nil {
fmt.Println(err.Error())
}
ping := &riak.PingCommand{}
// func (c *Cluster) Stop() (err error)
// Execute (synchronously) the provided Command against the
// active pooled Nodes using the NodeManager
if err = cluster.Execute(ping); err != nil {
fmt.Println(err.Error)
} else {
fmt.Println("ping passed")
}
listKeys(cluster)
}
func listKeys(c *riak.Cluster) {
var cmd riak.Command
// type Command interface {
// Name() string
// Success() bool
// Error() error
// // contains filtered or unexported methods
// }
cmd, err := riak.NewListKeysCommandBuilder().
WithBucket("moss.users").
WithStreaming(false).
Build()
if err != nil {
ErrExit(err)
}
if err = c.Execute(cmd); err != nil {
fmt.Println(err.Error)
} else {
fmt.Println("svc passed")
}
svc := cmd.(*riak.ListKeysCommand)
res := svc.Response
fmt.Println(res.Keys)
fmt.Println(reflect.TypeOf(res))
}
goroutineの実行が待たされない. exit immediately
だけが出力される。
package main
import (
"fmt"
"time"
)
func f() {
time.Sleep(time.Second * 2)
fmt.Println("2 seconds sleeped")
}
func main() {
go f()
fmt.Println("exit immediate")
}
待ちたい場合はsync.WaitGroupを使う. 下のバージョンは 2 seconds sleeped
も出力される
package main
import (
"fmt"
"time"
"sync"
)
func f(wg *sync.WaitGroup) {
defer wg.Done()
time.Sleep(time.Second * 2)
fmt.Println("2 seconds sleeped")
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
go f(&wg)
wg.Wait()
fmt.Println("exit after goroutine completed")
}
Deferred function calls are executed in Last In First Out
order after the surrounding function returns.
This function prints 3210
:
package main
import (
"fmt"
)
func main() {
b()
}
func b() {
for i := 0; i < 4; i++ {
defer fmt.Print(i)
}
}
TickerとTimerのChannelからメッセージ送られてきて、selectで取得
package main
import (
"fmt"
"time"
)
func main() {
timeChan := time.NewTimer(time.Second).C
tickChan := time.NewTicker(time.Millisecond * 400).C
doneChan := make(chan bool)
go func() {
time.Sleep(time.Second * 2)
doneChan <- true
}()
for {
select {
// Timerのchannelからメッセージが送られてくる
case <- timeChan:
fmt.Println("Timer expired")
case <- tickChan:
fmt.Println("Ticker ticked")
case <- doneChan:
fmt.Println("Done")
return
}
}
}
Ticker
package main
import (
"fmt"
"time"
)
func main() {
// func NewTicker(d Duration) *Ticker
ticker := time.NewTicker(time.Millisecond * 500)
go func() {
// type Ticker struct {
// C <-chan Time // The channel on which the ticks are delivered.
// // contains filtered or unexported fields
// }
for t := range ticker.C {
// t -> 2016-09-29 10:48:21.143446874 +0900 JST
fmt.Println("Tick at", t)
}
}()
time.Sleep(time.Millisecond * 1600)
ticker.Stop()
fmt.Println("Ticker stopped")
}
We often want to execute Go code at some point in the future, or repeatedly at some interval. Go’s built-in timer
and ticker
features make both of these tasks easy. We’ll look first at timers and then at tickers.
package main
import (
"fmt"
"time"
)
func main() {
// This timer will wait 2 seconds
timer1 := time.NewTimer(time.Second * 2)
// <- timer1.C blocks on the timer's channel C until it sends a value indicating that the timer expired
<- timer1.C
fmt.Println("Timer 1 expired")
// timer1がexpireした後にここから実行される
timer2 := time.NewTimer(time.Second)
go func() {
<- timer2.C
fmt.Println("Timer 2 expired")
}()
stop2 := timer2.Stop()
if stop2 {
fmt.Println("Timer 2 stopped")
}
}
doit
関数にのアドレス渡さないと、main関数の中のWaitGroupに影響与えられない。
package main
import (
"fmt"
"time"
"sync"
)
func main() {
workerCount := 2
var wg sync.WaitGroup
for i := 0; i < workerCount; i++ {
wg.Add(1)
go doit(i, &wg)
}
time.Sleep(1 * time.Second)
wg.Wait()
fmt.Println("all done!")
}
// 二番目の引数はポインタである必要がある
// ポインターでないとただmain関数のWaitGroupの
// コピーを使っているだけで、main関数のWaitGroupに影響しない
func doit(workerId int, wg *sync.WaitGroup) {
fmt.Printf("[%v] is running\n",workerId)
defer wg.Done()
time.Sleep(3 * time.Second)
fmt.Printf("[%v] is done\n",workerId)
}
Catコマンド -n
オプションつけると、ラインナンバーつけられる
// ./play -n play.go
package main
import (
"bufio"
"flag"
"os"
"fmt"
"io"
)
var numberFlag = flag.Bool("n", false, "number each line")
func cat(r *bufio.Reader) {
i := 1
for {
// func (b *Reader) ReadBytes(delim byte) ([]byte, error)
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often io.EOF).
buf, err := r.ReadBytes('\n')
if err == io.EOF {
break
}
if *numberFlag {
fmt.Fprintf(os.Stdout, "%5d %s", i, buf)
i++
} else {
fmt.Fprintf(os.Stdout, "%s", buf)
}
}
return
}
func main() {
flag.Parse()
// NArg is the number of arguments remaining after flags have been processed.
// つまり -nをマイナスした後の数, ファイルリストが続く
if flag.NArg() == 0 {
cat(bufio.NewReader(os.Stdin))
}
for i := 0; i < flag.NArg(); i++ {
fd, err := os.Open(flag.Arg(i))
if err != nil {
fmt.Fprintf(os.Stderr, "%s: error reading from %s: %s\n", os.Args[0], flag.Arg(i), err.Error())
continue
}
// オープンしたファイルに対して、bufio.NewReaderを呼び出す
cat(bufio.NewReader(fd))
}
}
The following is a program implementing a simple doubly linked list
supporting
int values.
package main
import (
"errors"
"fmt"
)
type Value int
type Node struct {
Value
prev, next *Node
}
type List struct {
head, tail *Node
}
func (l *List)Front() *Node {
return l.head
}
func (n *Node)Next() *Node {
return n.next
}
func (l *List)Push(v Value) *List {
n := &Node{Value: v}
// fmt.Printf("%v:", n)
if l.head == nil {
l.head = n
} else {
l.tail.next = n
n.prev = l.tail
}
l.tail = n
return l
}
var errEmpty = errors.New("List is empty")
func (l *List)Pop()(v Value, err error) {
if l.tail == nil {
err = errEmpty
} else {
v = l.tail.Value
l.tail = l.tail.prev
if l.tail == nil {
l.head = nil
}
}
return v, err
}
func main() {
l := new(List)
l.Push(2)
l.Push(4)
l.Push(6)
for n := l.Front(); n != nil; n = n.Next() {
fmt.Printf("%v\n", n.Value)
}
fmt.Println()
for v, err := l.Pop(); err == nil; v, err = l.Pop() {
fmt.Printf("%v\n", v)
}
}
a useful function is the fmt
package's Errorf
. It formats a string according to Printf
's rules and returns it as an error created by errors.New
.
if f < 0 {
return 0, fmt.Errorf("math: square root of negative number %g", f)
}
Here's how you might use errors.New
:
func Sqrt(f float64) (float64, error) {
if f < 0 {
return 0, errors.New("math: square root of negative number")
}
// implementation
}
The most commonly-used error implementation is the errors
package's unexported errorString
type.
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
You can construct one of these values with the errors.New function. It takes a string that it converts to an errors.errorString and returns as an error value.
// New returns an error that formats as the given text.
func New(text string) error {
return &errorString{text}
}
簡単なLinked Listを組み立てる
package main
import (
"fmt"
"container/list"
)
func main() {
l := list.New()
l.PushBack(1)
l.PushBack(2)
l.PushBack(4)
for e := l.Front(); e != nil; e = e.Next(){
fmt.Printf("%v\n", e.Value)
}
}
データの中身不明の場合、中身を2倍にする [1,2,3,4]
なら [2,4,6,8]
、["a","b"]なら ["aa", "bb"]
package main
import "fmt"
type e interface {}
func mult2(f e) e {
switch f.(type) {
case int:
return f.(int) * 2
case string:
return f.(string) + f.(string)
}
return f
}
func Map(n []e, f func(e) e) []e {
// 新たなinterface sliceを用意して、f関数の実行結果を入れる
m := make([]e, len(n))
for i, v := range n {
m[i] = f(v)
}
return m
}
func main() {
// interface eの中にどんなものも入る
m := []e{1,2,3,4}
s := []e{"a", "b", "c", "d"}
// Map関数がinterfaceの中のものをdoubleにする
// つまりMap関数はどんなものでも受け入れる
// intなら かける2
// stringなら 文字列連結
mf := Map(m, mult2)
sf := Map(s, mult2)
fmt.Printf("%v\n", mf)
fmt.Printf("%v\n", sf)
}
すでにあるJSONをGolangのMapに変換したい、keyはstringで、valueはいろんなタイプである可能性があるので Mapの定義は map[string]interface{}
にする
package main
import (
"fmt"
"encoding/json"
"reflect"
)
var input = `
{
"created_at": "Thu May 31 00:00:01 +0000 2012",
"value": 2
}
`
func main(){
var val map[string]interface{}
// func Unmarshal(data []byte, v interface{}) error
// Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v.
// our target will be of type map[string]interface{}, which is a
// pretty generic type that will give us a hashtable whose keys are strings,
// and whose values are of type interface{}
if err := json.Unmarshal([]byte(input), &val); err != nil {
panic(err)
}
fmt.Println(val)
for k, v := range val {
fmt.Println(k, reflect.TypeOf(v))
}
}
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go
If you write a function that takes an interface{}
value as a parameter, you can supply that function with any value.
func DoSomething(v interface{}) {
// ...
}
will accept any parameter whatsoever. v
is not of any type; it is of interface{}
type.
Go runtime will perform a type conversion (if necessary), and convert the value to an interface{}
value. All values have exactly one type at runtime, and v
’s one static type is interface{}
.
package main
import (
"fmt"
)
func PrintAll(vals []interface{}) {
for _, val := range vals {
fmt.Println(val)
}
}
func main() {
names := []string{"stanley", "david", "oscar"}
vals := make([]interface{}, len(names)) // 必須
for i, v := range names {
vals[i] = v
}
PrintAll(vals) // PrintAll(names)はうまくいかない
}
package main
import "fmt"
type Animal interface{
Speak() string
}
type Dog struct {
}
func(d Dog) Speak() string{
return "Woof!"
}
type Cat struct {
}
func (c *Cat) Speak() string{
return "Meow!"
}
type Llama struct {
}
func (l Llama) Speak() string {
return "??????"
}
type JavaProgrammer struct {
}
func (j JavaProgrammer) Speak() string {
return "Design patterns!"
}
func main(){
animals := []Animal{Dog{}, new(Cat), Llama{}, JavaProgrammer{}}
for _, animal := range animals {
fmt.Println(animal.Speak())
}
}
環境変数の設定の取得
package main
import "fmt"
import "strings"
import "os"
func main(){
os.Setenv("FOO", "1")
fmt.Println("FOO", os.Getenv("FOO"))
fmt.Println("BAR", os.Getenv("BAR"))
fmt.Println()
for _, e := range os.Environ() {
pair := strings.Split(e, "=")
fmt.Println("pair[0]:", pair[0], " pair[1]:", pair[1])
}
}
虚数
package main
import "fmt"
func main(){
var x complex128 = complex(1, 2)
var y complex128 = complex(3, 4)
fmt.Println(x*y) // (-5+10i)
fmt.Println(real(x*y)) // -5
fmt.Println(imag(x*y)) // 10
}
A WaitGroup
waits for a collection of goroutines to finish.
Add
adds delta, which may be negative, to the WaitGroup counter. Add
should execute before the statement creating the goroutine or other event to be waited for.
package main
import "fmt"
import "sync"
import "net/http"
func main() {
var wg sync.WaitGroup
var urls = []string{
"http://www.golang.org/",
"http://www.google.com",
"http://www.somestupidname.com",
}
for _, url := range urls {
// func (wg *WaitGrup) Add(delta int)
// Increment the WaitGroup counter.
wg.Add(1)
go func(url string) {
// Decrement the WaitGroup counter when the goroutine completes.
defer wg.Done()
fmt.Println("fetching ", url)
http.Get(url)
}(url)
}
// Wait for all HTTP fetches to complete
wg.Wait()
// Waitがブロックしているから、最後にこれが出力される
fmt.Println("Last Statement")
}
bytes
package
type Buffer struct {
}
A Buffer is a variable-sized buffer of bytes with Read and Write methods. The zero value for Buffer is an empty buffer ready to use.
package main
import "bytes"
import "fmt"
import "os"
func main() {
var b bytes.Buffer // A Buffer needs no initialization
// func (b *Buffer) Write(p []byte) (n int, err error)
b.Write([]byte("Hello "))
fmt.Fprintf(&b, "world\n")
// func (r *Reader) WriteTo(w io.Writer) (n int64, err error)
b.WriteTo(os.Stdout)
}
Json処理するためのstruct中の json:"page"
いみを出力を見るとわかる
https://blog.golang.org/json-and-go
package main
import "encoding/json"
import "fmt"
func main() {
type Response1 struct {
Page int
Fruits []string
}
type Response2 struct {
Page int `json:"page"` // pageは実際のフィールド名になる
Fruits []string `json:"fruits"`
}
res1D := &Response1{
Page: 1,
Fruits: []string{"apple", "peach", "pear"},
}
res2D := &Response2{
Page: 1,
Fruits: []string{"apple", "peach", "pear"},
}
// b, err != json.Marshal(m)
// If all is well, err will be nil, and b will be a []byte containing this JSON data.
// b == []byte(`{"Name":"Alice","Body":"Hello","Time":1294706395881547000}`)
res1B, _ := json.Marshal(res1D)
// {"Page":1,"Fruits":["apple","peach","pear"]}
fmt.Println(string(res1B))
res2B, _ := json.Marshal(res2D)
// {"page":1,"fruits":["apple","peach","pear"]}
fmt.Println(string(res2B))
}
Another way to create a variable is to use the built-in function new
. The expression new(T)
creates an unnamed variable of type T, initializes it the zero value of T, and returns its address, which is a value of type *T
.
p := new(int)
fmt.Println(*p)
*p = 2
fmt.Println(*p)
Each all to new
returns a distinct variable with a unique address
p := new(int)
q := new(int)
fmt.Println(p == q) // "false"
httpパッケージのListenAndServeのドキュメントを調べる
go doc http.ListenAndServe
If two concurrent requests try to update count at the same time, it might not be incremented consistently; the program would have a serious bug called a race condition. To avoid this problem, we must ensure that at most one goroutine accesses the variable at a time, which is the purpose of the mutex.Lock()
and mutex.Unlock()
calls that bracket each access of count.
package main
import (
"fmt"
"log"
"net/http"
"sync"
)
var mutex sync.Mutex
var count int
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/count", counter)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
mutex.Lock()
count++
mutex.Unlock()
// $ curl localhost:8000/a/b/c
// URL.Path = "/a/b/c"
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}
func counter(w http.ResponseWriter, r *http.Request) {
// counter関数がcount変数にアクセスする際にロックしておく
// 更新されないように
mutex.Lock()
fmt.Fprintf(w, "Count %d\n", count)
mutex.Unlock()
}
fetch関数をgoroutineで実行する。複数のurlリンクを同時にとる
io.Discard
var Discard io.Writer = devNull(0)
Discard
is an io.Writer
on which all Write calls succeed without doing anything.
func fetch(url string, ch chan <- string) {
start := time.Now()
fmt.Println("fetch start:", start)
resp, err := http.Get(url)
if err != nil {
ch <- fmt.Sprint(err)
return
}
// A successful Copy returns err == nil,
// not err == EOF. Because Copy is defined to read from src until EOF,
// it does not treat an EOF from Read as an error to be reported.
nbytes, err := io.Copy(ioutil.Discard, resp.Body)
// dont leak resource
resp.Body.Close()
if err != nil {
ch <- fmt.Sprintf("while reading %s: %v", url, err)
return
}
secs := time.Since(start).Seconds()
ch <- fmt.Sprintf("%.2fs %7d %s", secs, nbytes, url)
}
func ReadAll(r io.Reader) ([]byte, error)
ioutil.ReadAll
reads from r until an error or EOF and returns the data it read. A successful call returns err == nil, not err == EOF. Because ReadAll is defined to read from src until EOF, it does not treat an EOF from Read as an error to be reported.
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
)
func main() {
// index, url
for _, url := range os.Args[1:] {
resp, err := http.Get(url)
if err != nil {
fmt.Fprintf(os.Stderr, "fetch: %v\n", err)
os.Exit(1)
}
b, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "fetch: reading %s: %v\n", url, err)
os.Exit(1)
}
fmt.Printf("%s", b)
}
}
Closureを利用して、handlerで処理すると同時にhandlerの処理時間をclosureを利用して、測る
package main
import (
"fmt"
"net/http"
"time"
)
// Closureを利用して、ハンドラの処理はどのぐらいの時間を使ったかを測る
func main() {
// http.HandleFunc("/", hello) のように書いてもいい、HandleFuncの二個目の引数はの関数
// つまり 時間を測るとしても timed(hello)自体は関数である必要がある、なのでtimed()の戻り値は関数である
http.HandleFunc("/", timed(hello))
http.ListenAndServe(":8080", nil)
}
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "<h1>Hello!</h1>")
}
// timedの一つ目の引数は helloという関数に当てはまる。
// 戻り値の関数はまさにhelloと同じ形
func timed(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
f(w, r)
end := time.Now()
fmt.Println("The request took", end.Sub(start))
}
}
Closure
package main
import "fmt"
func main() {
counter := newCounter()
// we can persist data between function calls while also isolating the data(この例では n) from other code.
fmt.Println(counter())
fmt.Println(counter())
}
func newCounter() func() int {
n := 0
return func() int {
n += 1
return n
}
}
実行
$ go run main.go
1
2
Create Golang package
A package is a directory inside your $GOPATH/src
directory
export GOPATH=$HOME/Playground/Golang
mkdir -p ~/Playground/Golang/src/github.com/ColdFreak/golang-execise
cd ~/Playground/Golang/src/github.com/ColdFreak/golang-execise
touch main.go
mkdir mylib
touch mylib/testing101.go
main.go
ファイル
package main
import "fmt"
import "github.com/ColdFreak/golang-execise/mylib"
func main() {
fmt.Println(testing101.Sum([]int{1,2,3}))
}
mylib/testing101.go
ファイル
package testing101
func Sum(num []int) int {
sum := 0
for _, v := range num {
sum += v
}
return sum
}
実行
cd ~/Playground/Golang/src/github.com/ColdFreak/golang-execise
go build
~/Playground/Golang/src/github.com/ColdFreak/golang-execise/mylib/testing101.go
パッケージのテストを書く
touch ~/Playground/Golang/src/github.com/ColdFreak/golang-execise/mylib/testing101_test.go
cd ~/Playground/Golang/src/github.com/ColdFreak/golang-execise/mylib/
go test -v
testing101_test.go
ファイル
package testing101
import "testing"
func TestSum(t *testing.T) {
numbers := []int{1,2,3,4}
expected := 10
actual := Sum(numbers)
if actual != expected {
t.Errorf("Expected the sum of %v to be %d but instead got %d!", numbers, expected, actual)
}
}
コマンドラインにファイルあるかどうかを判断判断して、なかったらos.Stdinから入力を処理、あれば、逐次にファイルを処理する。 一回以上入力した行の回数を出力
import "fmt"
import "os"
import "bufio"
func main() {
counts := make(map[string]int)
files := os.Args[1:]
if len(files) == 0 {
fmt.Fprintf(os.Stderr, "from stdin")
countLines(os.Stdin, counts)
printRes(counts)
} else {
countFileLines(files, counts)
printRes(counts)
}
}
func countLines(f *os.File, counts map[string]int) {
input := bufio.NewScanner(f)
for input.Scan() {
counts[input.Text()]++
}
}
func countFileLines(fileList []string, counts map[string]int) {
for _, file := range fileList {
f, err := os.Open(file)
if err != nil {
fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
continue
}
countLines(f, counts)
f.Close()
}
}
func printRes(counts map[string]int) {
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
標準入力からのテキストを処理する bufio.NewScanner
, Scan()
, Text()
一回以上入力した行の回数を出力
package main
import "fmt"
import "os"
import "bufio"
func main() {
counts := make(map[string]int)
input := bufio.NewScanner(os.Stdin)
for input.Scan() {
counts[input.Text()]++
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
}
}
}
os.Args
は配列
go build play.go
./play ab cd ef
package main
import "fmt"
import "os"
func main() {
s, sep := "", ""
for _, arg := range os.Args[1:] {
s += sep + arg
sep = " "
}
fmt.Println(os.Args) // [./play ab cd ef]
fmt.Println(s) // ab cd ef
}
If an explicit period (.) appears instead of a name, all the package's exported identifiers will be declared in the current file's file block and can be accessed without a qualifier.
Assume we have compiled a package containing the package clause package math, which exports function Sin, and installed the compiled package in the file identified by "lib/math". This table illustrates how Sin may be accessed in files that import the package after the various types of import declaration.
import "lib/math" math.Sin
import M "lib/math" M.Sin
import . "lib/math" Sin
flagパッケージでコマンドラインをパース
package main
// flag package supporting basic commandline flag parsing
import "flag"
import "fmt"
func main() {
wordPtr := flag.String("word", "foo", "a string")
numPtr := flag.Int("numb", 42, "an int")
boolPtr := flag.Bool("fork", false, "a bool")
// -svarで受け取った値はsvar変数に設定される
var svar string
// Note that we need to pass in a pointer to the flag declaration function.
flag.StringVar(&svar, "svar", "bar", "a string var")
flag.Parse()
fmt.Println("word", *wordPtr)
fmt.Println("numb", *numPtr)
fmt.Println("fork", *boolPtr)
fmt.Println("svar", svar)
fmt.Println("tail", flag.Args())
}
net/http
を使う簡単なサーバー
ResponseWriterとRequestの詳細は下のリンクを参照
http://soryy.com/blog/2014/not-another-go-net-http-tutorial/
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path) // localhost:8080/you -> I love /you
fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) // localhost:8080/you -> I love you
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
Here we’ll look at using the sync/atomic package for atomic counters accessed by multiple goroutines.
package main
import (
"fmt"
"time"
"sync/atomic"
"runtime"
)
func main() {
var ops uint64 = 0
// 50個のgoroutines無限にopsをプラス1しようとしている
for i := 0; i < 50; i++ {
go func() {
for {
// to atomically increment the counter
atomic.AddUint64(&ops, 1)
// Allow other goroutines to proceed
runtime.Gosched()
}
}()
}
// Wait a second to allow some ops to accumulate.
time.Sleep(time.Second)
// In order to safely use the counter while it’s still being updated by other goroutines,
// we extract a copy of the current value into opsFinal via LoadUint64.
// As above we need to give this function the memory address &ops from which to fetch the value.
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
同時に3つのワーカーで9つのjobを処理する
package main
import (
"fmt"
"time"
)
// jobs channelはデータを取り出すために
// results channelはデータを送り込むため
func worker(worker_id int, jobs <-chan int, results chan<- int) {
for job := range jobs {
fmt.Println("worker", worker_id, "processing job", job)
time.Sleep(time.Second)
results <- (job * 2)
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// This starts up 3 workers, initially blocked because there
// are no jobs yet.
for w:= 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// Here we send 9 jobs and then close that channel to indicate that's all the work we have
for j:= 1; j <= 10; j++ {
jobs <- j
}
close(jobs)
for a := 1; a <= 9; a++ {
<-results
}
}
Use os.Exit
to immediately exit with a given status.
defers
will not be run when using os.Exit, so this fmt.Println will never be called.
package main
import (
"fmt"
"os"
)
func main() {
defer fmt.Println("!")
os.Exit(3)
}
Sometimes we’d like our Go programs to intelligently handle Unix signals. For example, we might want a server to gracefully shutdown when it receives a SIGTERM, or a command-line tool to stop processing input if it receives a SIGINT.
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
func main() {
// create a channel to receive signals
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
// signal.Notify registers the given channel to receive notifications of
// the specified signals
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <- sigs
fmt.Println()
fmt.Println(sig) // ^C interrupt
done <- true
}()
fmt.Println("awaiting signal")
<- done
fmt.Println("exiting")
}
Spawning processes from Go.The exec.Command
helper creates an object to represent this external process.
.Output
is another helper that handles the common case of running a command, waiting for it to finish, and collecting its output. If there were no errors, dateOut will hold bytes with the date info.
package main
import (
"fmt"
"os/exec"
)
func main() {
dateCmd := exec.Command("date")
dateOut, err := dateCmd.Output()
if err != nil {
panic(err)
}
fmt.Println(string(dateOut))
}
We use the type
keyword before the name of the struct. The Location here is not an instance—it is something we must create with new.
In main, we see the syntax for creating an instance of struct type. new()
is a built-in function.
package main
import (
"fmt"
)
type Location struct {
x int
y int
valid bool
}
func main() {
loc := new(Location)
loc.x = 10
fmt.Println(loc.x) // 10
fmt.Println(loc.y) // 0
fmt.Println(loc.valid) // false
}
Checking the equality of two slices.
DeepEqual
is a recursive relaxation of Go's == operator.
http://stackoverflow.com/questions/15311969/checking-the-equality-of-two-slices
package main
import (
"fmt"
"reflect"
)
func main() {
a := []int{1,2,3}
b := []int{1,2,3}
c := []int{1,2,2}
fmt.Println(reflect.DeepEqual(a,b)) // true
fmt.Println(reflect.DeepEqual(a,c)) // false
}
Use ioutil
only if you're sure you're not dealing with big files.
package main
import (
"io/ioutil"
)
func main() {
// func ReadFile(filename string) ([]byte, error)
b, err := ioutil.ReadFile("input.txt")
if err != nil {
panic(err)
}
// func WriteFile(filename string, data []byte, perm os.FileMode) error
// writes data to a file named by filename. If the file does not exist,
// WriteFile creates it with permissions perm;
err = ioutil.WriteFile("outout.txt", b, 0644)
if err != nil {
panic(err)
}
}
Golangのtimeとrand
func main() {
fmt.Println(time.Now()) // 2016-09-20 13:12:08.419840527 +0900 JST
fmt.Println(time.Now().UnixNano()) // 1474344754666866248
s1 := rand.NewSource(time.Now().UnixNano())
r1 := rand.New(s1)
fmt.Println(r1.Intn(100)) // 毎回違う値 0 <= n < 100
fmt.Println(r1.Float64()) // 毎回違う値 0.0 <= n < 1.0
}
bufio
を使って、ファイルの読み書きを行う
package main
import(
"bufio"
"io"
"os"
)
func main() {
fi, err := os.Open("input.txt")
if err != nil {
panic(err)
}
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
// NewReader returns a new Reader whose buffer has the default size.
r := bufio.NewReader(fi)
fo, err := os.Create("output.txt")
if err != nil {
panic(err)
}
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()
// func NewWriter(w io.Writer) *Writer
// NewWriter returns a new Writer whose buffer has the default size.
w := bufio.NewWriter(fo)
// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
for {
// func (b *Reader) Read(p []byte) (n int, err error)
// reads data into p. It returns the number of bytes read into p.
n, err := r.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if (n == 0) {
break
}
// func (b *Writer) Write(p []byte) (nn int, err error)
// writes the contents of p into the buffer, it returns the number of bytes written.
// If nn < len(p), it also returns an error explaining why the write is short.
if _, err := w.Write(buf[:n]); err != nil {
panic(err)
}
}
// Flush writes any buffered data to the underlying io.Writer
if err = w.Flush(); err != nil {
panic(err)
}
}
crypto/sha1
を使って、文字列をhashする
package main
import (
"fmt"
"crypto/sha1"
)
func main() {
s := "sha1 this string"
// The pattern for generating a hash
h := sha1.New()
// `Write` expects bytes. If you have a string
// use []byte(s) to coerce it to bytes
h.Write([]byte(s))
// This gets the finalized hash result as a byte slice.
// The argument to Sum can be used to append to an existing
// byte slice: it usually isn't needed
result := h.Sum(nil)
fmt.Println(s)
fmt.Printf("%x\n", result)
}
Tick
は重複に実行される.After
は一回だけ実行される
func main() {
tick := time.Tick(100 * time.Millisecond)
boom := time.After(500 * time.Millisecond)
for {
select {
case <-tick:
fmt.Println("tick.")
case <-boom:
fmt.Println("BOOM.")
return
default:
fmt.Println(" .")
time.Sleep(50 * time.Millisecond)
}
}
}
fibonacci関数が無限ループ,quitチャンネルに何か入ってきたら中断する
package main
import "fmt"
func fibonacci(c, quit chan int) {
x, y := 0, 1
for true {
select {
case c <- x:
x, y = y, x+y+2
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
Golang String manipulation
sample := "Hello World"
fmt.Println(strings.Contains(sample, "lo")) // true
fmt.Println(strings.Index(sample, "lo")) // 3
fmt.Println(strings.Count(sample, "l")) // 3
fmt.Println(strings.Replace(sample, "l", "x", 2)) // Hexxo World
fmt.Println(strings.Split(sample, " ")) // [Hello World]
sortString := []string{"c", "a", "b"}
sort.Strings(sortString)
fmt.Println(sortString) // [a b c]
joinString := strings.Join([]string{"3", "2", "1"}, "|")
fmt.Println(joinString) // 3|2|1
関数helloの中にdeferが呼ばれているため呼ばれているため,helloが実行完了したら, deferが実行されるけど,finalの前に実行される
func main() {
hello()
fmt.Println("final")
}
func hello() {
defer fmt.Println("End")
fmt.Println("Start")
}
Closure
func main() {
num := 2
doubleNum := func() int {
return num * 2
}
fmt.Println(doubleNum())
}
How to find a type of a object in Golang? The Go reflection package has methods for inspecting the type of variables.
The following snippet will print out the reflection type of a string, integer and float.
package main
import (
"fmt"
"reflect"
)
func main() {
tst := "string"
tst2 := 10
tst3 := 1.2
fmt.Println(reflect.TypeOf(tst)) // string
fmt.Println(reflect.TypeOf(tst2)) // int
fmt.Println(reflect.TypeOf(tst3)) // float64
}
With Marshal
and Unmarshal
, we convert to JSON data and from JSON data.
Only one method call is required. Bytes are returned, but we can change these to strings in Go.
package main
import (
"encoding/json"
"fmt"
)
type Box struct {
Width int
Height int
Color string
Open bool
}
func main() {
box := Box{
Width: 10,
Height: 20,
Color: "blue",
Open: false,
}
// [123 34 87 105 100 116 104 34 58 49 48 44 34 72 101 105 103 104 116 34 58 50 48 44 34 67 111
// 108 111 114 34 58 34 98 108 117 101 34 44 34 79 112 101 110 34 58 102 97 108 115 101 125]
b, _ := json.Marshal(box)
// We convert our bytes (b) to a string and display them with fmt.Println.
s := string(b)
// {"Width":10,"Height":20,"Color":"blue","Open":false}
fmt.Println(s)
}
How to convert an int value to string in Go?
t := strconv.Itoa(123)
fmt.Println(t)
How to read/write from/to file in Go http://stackoverflow.com/questions/1821811/how-to-read-write-from-to-file
package main
import (
"io"
"os"
)
func main() {
// open input file
fi, err := os.Open("input.txt")
if err != nil {
panic(err)
}
// close fi on exit and check for its returned error
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
// open output file
fo, err := os.Create("output.txt")
if err != nil {
panic(err)
}
// close fo on exit and check for its returned error
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()
// make a buffer to keep chunks that are read
buf := make([]byte, 1024)
for {
// read a chunk
n, err := fi.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
if n == 0 {
break
}
// write a chunk
if _, err := fo.Write(buf[:n]); err != nil {
panic(err)
}
}
}
Iterating over all the keys of a Golang map
m := map[string]string{ "key1":"val1", "key2":"val2" };
for k := range m {
fmt.Printf("%s -> %s\n", k, m[k])
}
How to check if a file exists in Go?
you can directly use os.Stat
and os.IsNotExist
in a single line.
if _,err := os.Stat("/tmp/output"); os.IsNotExist(err) {
fmt.Println("file is not exist")
}
The cap()
built-in tells us the internal allocation heuristics of a slice.
When it runs out of room, a slice's array doubles in size
.
Here: We create a slice of three elements. Its cap is 3.
We then add a fourth element, and its capacity doubles to 6.
elements := []int{100,200,300}
fmt.Println(cap(elements))
elements = append(elements, 400)
fmt.Println(cap(elements))
How to check if a map contains a key in go?
evaluates ok
, which will be true
if foo
was in the map
m := map[string]int{"foo": 1, "bar": 2}
if _, ok := m["foo"]; ok {
fmt.Println("foo exists")
}
How do you write multiline strings in Go?
func main() {
s := `line 1
line 2
line 3`
fmt.Println(s)
}
How to efficiently concatenate strings in Go?
The best way is to use the bytes
package. It has a Buffer
type which implements io.Writer
.
This does it in O(n)
time.
package main
import (
"bytes"
"fmt"
)
func main() {
var buffer bytes.Buffer
for i := 0; i < 10; i++ {
buffer.WriteString("a")
}
fmt.Println(buffer.String())
}
By default channels are unbuffered
, meaning that they will only accept sends (chan <-) if there is a corresponding receive (<- chan) ready to receive the sent value. Buffered channels
accept a limited number of values without a corresponding receiver for those values.
// we make a channel of strings buffering up to 2 values.
messages := make(chan string, 2)
messages <- "buffered"
messages <- "channel"
fmt.Println(<- messages)
fmt.Println(<- messages)
Create a new channel with make(chan val-type)
.
Send a value into a channel using the channel <-
syntax.
The <-channel
syntax receives a value from the channel.
messages := make(chan string)
go func () {
messages <- "ping"
}()
msg := <- messages
fmt.Println(msg)
You can also start a goroutine for an anonymous function call.
go func(msg string) {
fmt.Println(msg)
}("going")
We’ll implement this interface on rect and circle types.
package main
import "fmt"
import "math"
type geometry interface {
area() float64
perim() float64
}
type rect struct {
width, height float64
}
type circle struct {
radius float64
}
// To implement an interface in Go, we just need to implement all the methods in the interface.
// Here we implement geometry on rects.
func (r rect) area() float64 {
return r.width * r.height
}
func (r rect) perim() float64 {
return 2*r.width + 2*r.height
}
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}
func (c circle) perim() float64 {
return 2 * math.Pi * c.radius
}
func measure(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perim())
}
func main() {
r := rect{width: 3, height: 4}
c := circle{radius: 5}
// The circle and rect struct types both implement the geometry interface so we can use instances of these structs as arguments to measure.
measure(r)
measure(c)
}
Here’s a function that will take an arbitrary number of ints as arguments.
func sum(nums ...int){
total := 0
for _, num := range nums {
total += num
}
fmt.Println("total: ", total)
}
func main() {
sum(1,2,3) // Variadic functions can be called in the usual way with individual arguments.
nums := []int{2,3,4,5}
sum(nums...) // If you already have multiple args in a slice, apply them to a variadic function using func(slice...) like this.
}
The (int, int)
in this function signature shows that the function returns 2 ints.
func vals(a, b int) (int, int) {
return a, b
}
a, b := vals(1, 3)
fmt.Println("a, b = ", a, b) // a, b = 1 3
range
on arrays
and slices provides both the index and value for each entry.
// indexは0から始まる
nums := []int{2,3,4}
sum := 0
for index, num := range nums {
fmt.Println(index)
sum += num
}
fmt.Println("sum", sum)
range
on map
iterates over key/value pairs.
// make(map[key-type]val-type)
kvs := map[string]string{"a": "apple", "b": "banana"}
for k, v := range kvs {
fmt.Printf("%s -> %s\n", k, v)
}
The optional second return value when getting a value from a map indicates if the key was present in the map. This can be used to disambiguate between missing keys and keys with zero values like 0 or "". Here we didn’t need the value itself, so we ignored it with the blank identifier _.
// make(map[key-type]val-type)
m := map[string]int{"foo": 1, "bar": 2}
delete(m, "bar")
_, prs_foo := m["foo"]
_, prs_bar := m["bar"]
fmt.Println(prs_foo) // true
fmt.Println(prs_bar) // false
Go supports methods defined on struct types.
type rect struct {
width, height int
}
// This area method has a _receiver type_ of `*rect`.
func (r *rect) area() int {
return r.width * r.height
}
// Methods can be defined for either pointer or value
// receiver types. Here's an example of a value receiver.
func (r rect) perim() int {
return 2*r.width + 2*r.height
}
b := [...]string{"Pen", "Te", "mike"}
fmt.Println(len(b)) // 3
for without a condition will loop repeatedly until you break out of the loop or return from the enclosing function.
for {
fmt.Println("loop")
break
}
A statement can precede conditionals; any variables declared in this statement are available in all branches.
if num := 9; num < 0 {
fmt.Println(num, "is negative")
} else if num < 10 {
fmt.Println(num, "has 1 digit")
} else {
fmt.Println(num, "has multiple digits")
}
You can use commas to separate multiple expressions in the same case statement. We use the optional default case in this example as well.
switch time.Now().Weekday() {
case time.Saturday, time.Sunday:
fmt.Println("it's the weekend")
default:
fmt.Println("it's a weekday")
}
Array types are one-dimensional, but you can compose types to build multi-dimensional data structures.
var twoD [2][3]int
for i := 0; i < 2; i++ {
for j := 0; j < 3; j++ {
twoD[i][j] = i + j
}
}
To create an empty map, use the builtin make: make(map[key-type]val-type).
m := make(map[string]int)
You can also declare and initialize a new map in the same line with this syntax.
n := map[string]int{"foo": 1, "bar": 2} // Println(n) -> map[foo:1 bar:2]
The builtin delete removes key/value pairs from a map.
delete(m, "k2")
Here we use range to sum the numbers in a slice. Arrays work like this too.
nums := []int{2, 3, 4}
sum := 0
for _, num := range nums {
sum += num
}
Here we use the 2 different return values from the call with multiple assignment.
func vals() (int, int) {
return 3, 7
}
func main() {
a, b := vals()
}
range on strings iterates over Unicode code points. The first value is the starting byte index of the rune and the second the rune itself.
for i, c := range "go" {
fmt.Println(i, c)
}
Here’s a function that will take an arbitrary number of ints as arguments.
func sum(nums ...int) {
total := 0
for _, num := range nums {
total += num
}
fmt.Println(total)
}
func main() {
sum(1, 2, 3)
// If you already have multiple args in a slice,
// apply them to a variadic function using
// `func(slice...)` like this.
nums := []int{1, 2, 3, 4}
sum(nums...)
}
// 設定ファイルの情報を取得する関数のタイプを指定、違う関数でも同じタイプにする
type getInfo func(env string, vp *viper.Viper) interface{}
// Portの情報を設定ファイルからstructに読み込む
type PortInfo struct {
port string
}
// DB接続情報を設定ファイルからstructに読み込む
type DBInfo struct {
host string
database string
username string
password string
collection string
}
// loadConfigは情報取得関数のタイプを受け取る。新しい中間関数を返す
func loadConfig(fn getInfo) func(s string) interface{} {
vp := viper.New()
vp.SetConfigName("app")
vp.AddConfigPath("config")
err := vp.ReadInConfig()
if err != nil {
panic(err)
}
// 中間関数はenv文字列を受け取る。クロージャも利用して、上で定義しているvpをfn()関数の中で利用している
return func(env string) interface{} {
res := fn(env, vp)
return res
}
}
func getDBInfo(env string, vp *viper.Viper) interface{} {
var d = DBInfo{}
d.host = vp.GetString(fmt.Sprintf("%s.db_host", env))
d.database = vp.GetString(fmt.Sprintf("%s.db_database", env))
d.username = vp.GetString(fmt.Sprintf("%s.db_username", env))
d.password = vp.GetString(fmt.Sprintf("%s.db_password", env))
d.collection = vp.GetString(fmt.Sprintf("%s.db_collection", env))
return d
}