何度も調べるの面倒なので調べるついでにメモしていく。随時追加予定、順序は適当。
UnixTimeのepocミリ秒の計算
timeパッケージにはUnix()
とUnixNano()
しかメソッドがないので、ミリ秒で求めるにはミリ秒除算が必要。
import "time"
unixMilliSecond := time.Now().UnixNano() / int64(time.MilliSecond)
string -> []byte変換、またはその逆
キャストすればいい。
str := "Lorem Ipsum"
bytes := []byte(str)
str := string(bytes)
integer -> string変換、またはその逆
strconvパッケージを使う。
import strconv
n := 100
str := strconv.Itoa(n)
int64などはItoa()
では変換できないので、FormatInt()
を使う。
n := int64(100)
str := strconv.Itoa(n) // エラー
str := strconv.FormatInt(n, 10)
Atoi()
で文字列に。
n = strconv.Atoi(n)
追記 -------------------
fmt.Sprint(n)
でもできる。
n := 100
str := fmt.Sprint(n)
Sha1、Sha256
crypto/sha1
、crypto/sha256
パッケージを使う。
import "crypto/sha1"
str := "Lorem Ipsum"
encoder := sha1.New()
encoder.Write([]byte(str))
hash := encoder.Sum(nil)
fmt.Printf("%s sha1 crypto to %x", str, hash)
// -> "Lorem Ipsum encoded to 0646164d30b3bd0023a1e6878712eb1b9b15a1da"
[]byte
に変換してWriteしないといけないので注意。あと、%x
はhexなので、実際のhashはバイナリの[]byteになっている。hexで欲しい時はencoding/hex
パッケージを使って別途エンコードする。
import (
"crypto/sha1"
"encoding/hex"
)
str := "Lorem Ipsum"
encoder := sha1.New()
encoder.Write([]byte(str))
hash := encoder.Sum(nil)
hexHash := hex.EncodeToString(hash)
fmt.Printf("%s sha1 crypto to %s", str, hexHash)
// -> "Lorem Ipsum encoded to 0646164d30b3bd0023a1e6878712eb1b9b15a1da"
追記 -------------------
sha1.Sum([]byte)
直接できる、とのこと(なんで知らなかったのか…)
str := "Lorem Ipsum"
hash := sha1.Sum([]byte(str))
fmt.Printf("%s sha1 crypto to %x", str, hash)
// -> "Lorem Ipsum encoded to 0646164d30b3bd0023a1e6878712eb1b9b15a1da"
JSONエンコード、フィールド名指定
encoding/json
を使う。
import "encoding/json"
// JSON用
type JsonResponse struct {
UserId int
Name string
}
...
response =: &JsonResponse{
UserId: 1,
Name: "ysugimoto",
}
encoded, _ := json.Marshal(response)
fmt.Println(encoded)
// -> {"UserId":"1","Name":"ysugimoto"}
このままだとフィールド名がキャメルケースになってしまうので、バッククオートでフィールド名を指定できる。
// JSON用
type JsonResponse struct {
UserId int `json:"userid"`
Name string `json:"name"`
}
...
response =: &JsonResponse{
UserId: 1,
Name: "ysugimoto",
}
encoded, _ := json.Marshal(response)
fmt.Println(encoded)
// -> {"userid":"1","name":"ysugimoto"}
HTTPリクエスト送信
net/http
、bytes
パッケージを使う。
import (
"net/http"
"bytes"
)
data := "this is data"
req, err := http.NewRequest("POST", "http://localhost:9001", bytes.NewBuffer([]byte(data))
req.Header.Set("Content-Type", "application/www-x-form-urlencoded")
client := &http.Client{}
resp, reqErr := client.Do(req)
if reqErr != nil {
fmt.Printf("%v", reqErr)
}
resp.Body.Close()
最後にClose()
するのを忘れずに。defer
に登録してもいいのかな。
スライスの可変長引数展開渡し
可変長引数を受け付ける関数には、スライスを...
で展開して渡せる。
func main() {
// 普通にintを複数渡す
total := sum(10, 1, 2, 3)
fmt.Println(total) // 16
// スライスを展開して渡す
args := []int{1, 2, 3}
total2 := sum(10, args...)
fmt.Println(total2) // 16
}
// 第二引数以降が可変長の関数
func sum(base int, args ...int) int {
fmt.Println(args)
for i := range args {
base += i
}
return base
}
SQL文でプレースホルダに値をバインドするときにこのやり方が必要だった。
乱数生成
math/rand
パッケージを使う。乱数シードにタイムスタンプ使う場合。
import "math/rand"
import "time"
rand.Seed(time.Now().Unix())
r := rand.Int31() // 32bit-Int乱数
r := rand.Intn(10) // 0から10の範囲指定乱数
Hash-Hmacとか
crypto/hmac
を使う。crypto/sha1
、crypto/sha256
は用途に応じて。
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
secret := "foobar"
str := "Lorem Ipsum"
hash := hmac.New(sha256.New, []byte(secret))
hash.Write([]byte(str))
fmt.Println(hex.EncodeToString(hash.Sum(nil))
コマンドラインフラグ
flag
パッケージを使う。IntVar()
などで変数にバインドする方法と、Int()
で変数の戻り値を使う方法がある。
import "flag"
// 変数にバインドするパターン
var num int
flag.IntVar(&num, "n", 0, "Number")
fmt.Println(num)
// 変数の戻り値を使うパターン
num := flag.Int("n", 0, "Number")
fmt.Println(num)
いずれもnum
はコマンドラインの-n
オプションの値をポインタとして受け取る。実行するときは、フラグ名の後ろに半角スペース、またはイコールを付けないと正しく受け取れない。すなわち、
$ go run sample.go -n 10
>> 10
$ go run sample.go -n=10
>> 10
だが、
$ go run sample.go -n10
>> error
となるので注意。
コマンドライン引数
os.Args []string
から取得できる。が、上記のフラグも一緒に取ってしまうので、純粋な引数リストのみはフィルタリングしないといけなかった。そこで、別でフィルタリング用の関数を作って対処した。
import "os"
func main() {
// os.Args[0]はコマンド自身なので無視
arguments := parseArguments(os.Args[1:])
fmt.Printf("Arguments: %v\n", arguments)
}
// "-"がついた引数はフラグとしてスキップする
func parseArguments(args []string) (parsed []string) {
var r []rune
flagValue := false
for _, arg := range args {
r = []rune(arg)
if string(r[0]) == "-" {
flagValue = true
continue
} else if flagValue {
flagValue = false
continue
}
parsed = append(parsed, arg)
}
return
}
戻り値が初期化済みなので、そのままreturn
すればOK。これ初めて見た時すげーって思った。あと、この関数では単純にスイッチになっている引数が取れない(-sのみのフラグなど)。何かいい方法あれば教えて下さい…
$ go run sample.go -n 10 foo
>> Arguments: [foo]
ループ
Map
とArray
、Slice
はrange
式でループできる。range式はそれぞれ2値を戻す。
m := map[string]string{"foo": "bar", "Lorem": "Ipsum"}
// キー、値でループできる
for key, value := range m {
fmt.Printf("Key is %s, Value is %s\n", key, value)
}
s := []string{"foo", "bar", "baz"}
// インデックス、値でループできる
for ind, value := range s {
fmt.Printf("Index is %d, Value is %s\n",ind, value)
}
$ go run loop.go
Key is foo, Value is bar
Key is Lorem, Value is Ipsum
Index is 0, Value is foo
Index is 1, Value is bar
Index is 2, Value is baz
マップやスライスの存在チェック
マップは2つ目の値がnilかどうかで判定できる。スライスはlen()
でサイズ判定すればいいのかな?
m := map[string]string{"foo": "bar", "Lorem": "Ipsum"}
// 存在チェック
if v, ok := m["baz"]; ok {
// 存在した時の処理
}
s := []string{"foo", "bar", "baz"}
// 存在チェック
if len(s) > 1 {
// 存在した時の処理
}
このあたりどうするのがベストなんだろう。
キーボード入力
fmt.Scanln()
で入力待ち状態できる。
var input string
fmt.Print("What's your name?")
fmt.Scanln(&input)
fmt.Printf("Hello, %s!\n", input)
現在実行中のファイルパスの取得
いわゆる__FILE__
的なことがしたいときはruntime
パッケージを使う。
import "runtime"
…
_, filename, _, _ := runtime.Caller(1)
fmt.Println(filename) // 実行中のcurrent file pathが取得できる
runtime.Caller()
では他にも行番号も取得できる。path.Dir
と組み合わせれば__DIR__
もできるね。
日付処理
time
パッケージを使う。かなり独特の仕組みになってるけど、理解してしまえばなんのことはない。年月日などが特定の識別子になっていて、それを組み合わせてフォーマッタに使えばいい。見た感じ、識別子は以下の様な感じ。
- 年 "2006"
- 月 "01" または "Jan"
- 日 "02"
- 時 "15"
- 分 "04"
- 秒 "05"
- 時差 "-0700" とか "-07:00" とか
- 曜日 "Mon"
例えば、MySQLのDATETIME型に現在時刻を入れる時は以下のような感じで。
import "time"
dateTime := t.Now().Format("2006-01-02 15:04:05")
// Insert...
Gzip
オンザフライで作って圧縮後のサイズを読み取る処理。普通にファイルを操作するのはググれば出てくるので、動的に圧縮してデータを取得するサンプル。io.Writer/io.Readerをよくわかってない疑惑。
import "compress/gzip"
import "bytes"
import "io/ioutil"
import "fmt"
var data = []byte("0000111122223333444455556666777788889999")
func main() {
var b bytes.Buffer
// 圧縮
writer := gzip.NewWriter(&b) // NewWriterLevelでもいい
writer.Write(data)
// Flush/Closeしてからでないとバイトが取得できない
if err := writer.Flush(); err != err {
fmt.Printf("%w\n", err)
return
}
if err := writer.Close(); err != err {
fmt.Printf("%w\n", err)
return
}
// 読み取り
compressed = b.Bytes()
fmt.Println(compressed)
}