Skip to content

Instantly share code, notes, and snippets.

@wang-zhijun
Last active June 29, 2018 15:43
Show Gist options
  • Save wang-zhijun/8bfd749e90a29ae198920e3703804e33 to your computer and use it in GitHub Desktop.
Save wang-zhijun/8bfd749e90a29ae198920e3703804e33 to your computer and use it in GitHub Desktop.
Golang

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は同時にそれぞれ値truelockという名前の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.

working with transactions

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 はすべてのプロジェクトを一箇所で保管する

  1. GOPATH~/Playground/Goalngに設定
  2. mkdir -p $GOPATH/src/github.com/ColdFreak/hello
  3. touch $GOPATH/src/github.com/ColdFreak/hello/hello.go
  4. go install github.com/ColdFreak/hello
  5. hello.goがbuildされて、 helloコマンドが$GOPATH/bin/ディレクトリにインストールされる
  6. $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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment