コピペコードで快適生活

明日使えるソースを自分のために

Goことはじめ(JSONの取り扱い)

http://gihyo.jp/dev/feature/01/go_4beginners/0004 より学んだことメモ

package main

import (
	"fmt"
	"log"
	"encoding/json"
)

//
// 構造体にタグをつけることでJSON変換時の
// ルールを定義することができる
// 何も指定しない場合はpublicなフィールドだけ格納される
//
type Person struct {
	ID int `json:"id"` // id という名前で格納する
	Name string `json:"name"`
	Email string `json:"-"` // JSONに格納しない
	Age int `json:"age"`
	Address string `json:"address,omitempty"` // ,omitemptyで値が空なら無視
	memo string
}
// JSONへの変換
func JsonStringifyFunc() {
	fmt.Println("構造体からJSONへの変換 ---------- ")
	person := &Person {
		ID: 1,
		Name: "Gopher",
		Email: "gopher@example.org",
		Age: 5,
		Address: "",
		memo: "golang lover",
	}
	// 構造体にデータを代入して
	// ポインタを渡すだけで、
	// デフォルトフォーマットでJSON文字列の[]byteを生成できる
	b, err := json.Marshal(person)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(b))  // 文字列に変換
	// -> {"id":1,"name":"Gopher","age":5}
}
// JSONから構造体への変換
func JsonParseFunc() {
	fmt.Println("JSONから構造体への変換 ---------- ")
	var person Person
	b := []byte(`{"id":1,"name":"Hogeo","age":10}`)
	err := json.Unmarshal(b, &person)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(person)
}

func main() {
	JsonStringifyFunc()
	JsonParseFunc()
}

goenvインストールメモ

# インストール
$ git clone https://github.com/syndbg/goenv.git ~/.goenv

# ~/.bash_profile に追記
export GOENV_ROOT="$HOME/.goenv"
export PATH="$GOENV_ROOT/bin:$PATH"
eval "$(goenv init -)"

# 反映
source ~/.bash_profile

# 使えるバージョン確認
goenv install -l

# 指定バージョンをインストール
goenv install 1.12.3

# グローバルで使う
goenv global 1.12.3

# rehashするとGOPATHが切り替わる
goenv rehash
echo ${GOPATH}
/Users/kinosuke/go/1.12.3

# そのディレクリ以下で使う
goenv local 1.12.3

# インストール済のGo一覧
goenv versions

# depのインストール
# ※GOPATH以下にインストールされる
# npmみたいにパッケージをプロジェクトディレクトリ内にインストールできるようにするやつ
go get -u github.com/golang/dep/cmd/dep

# goenvの更新
cd $(goenv root)
git pull

※GOPATHとは
Go言語での開発時の作業ディレクトリ。環境変数GOPATHに保存される。
明示的な指定がない場合はデフォルト設定が使われる。

> If no GOPATH is set, it is assumed to be $HOME/go on Unix systems and %USERPROFILE%\go on Windows.

Goことはじめ3

第3章 型システム―型を用いた安全なプログラミング:はじめてのGo―シンプルな言語仕様,型システム,並行処理|gihyo.jp … 技術評論社
より学んだことメモ。

package main

import (
	"fmt"
)

//
// 型の拡張
// 同じ型でも違う意味を持つもの(同じintでもIDを表すものと優先度を表すものとか)を混同しちゃうとバグになるようなときに使う。
//
type ID int
type Priority int

func ProcessTask(id ID, priority Priority) {
	fmt.Println(id, priority);
}

func RunProcessTask() {
	fmt.Println("型の拡張 ---------- ")

	var id ID = 3
	var priority Priority = 5

	// typeが違うのでコンパイルエラーする
	// ProcessTask(priority, id)

	// typeが適合するのでこっちは通る
	ProcessTask(id, priority)
}


//
// 構造体
//
type Task struct {
	ID int
	Detail string	// パッケージ外にpublicな属性は先頭大文字
	done bool	// パッケージ内でprivateな属性は先頭小文字
}
func RunTask() {
	fmt.Println("構造体 ---------- ")

	// Task構造体の初期化
	// 値を与えなかった場合はゼロ値で初期化される
	var task Task = Task{
		ID: 1,
		Detail: "buy the milk",
		done: true,
	}

	// 定義順に値を渡すことでフィールド名を省略
	// var task Task = Task{1, "buy the milk", true}

	fmt.Println(task.ID)
	fmt.Println(task.Detail)
	fmt.Println(task.done)
}


//
// ポインタ型
// 引数の方を*Taskとすることでポインタを渡せる
// これで参照渡しができる
//
func Finish(task *Task) {
	task.done = true
}
func RunFinish() {
	fmt.Println("ポインタ型 ---------- ")
	// &Taskでポインタを渡せる
	task := &Task{done: false}
	Finish(task)
	fmt.Println(task.done) // true
}

//
// 構造体の初期化
// コンストラクタがないのでNew*というメソッドを作って初期化するのが通例
//
func NewTask(id int, detail string) *Task {
	// new()メソッドは
	// 構造体のフィールドをすべてゼロ値で初期化して返す
	var task *Task = new(Task)
	task.ID = id
	task.Detail = detail
	return task
}
func RunNewTask() {
	fmt.Println("構造体の初期化 ---------- ")
	task := NewTask(1, "buy the milk")
	fmt.Printf("%+v\n", task)
}


//
// 構造体にメソッドを追加する
// 
func (task Task) String() string {
	// レシーバのコピーがわたされるので
	// ここで値を変えてもオリジナルの値は変わらない
	str := fmt.Sprintf("%d) %s", task.ID, task.Detail)
	return str
}
func (task *Task) Finish() {
	// ポインタ渡しなのでオリジナルの値が変わる
	task.done = true
}
func RunTaskFunc() {
	fmt.Println("構造体のメソッド追加 ---------- ")
	task := NewTask(1, "buy the milk")
	fmt.Printf("%s\n", task)

	task.Finish()
	fmt.Printf("%s\n", task.done)
}


//
// インターフェース
//
// インターフェイスの定義
// 単純なインターフェースは*erという名前をつけるのが通例
type Stringer interface {
	String() string
}
// 引数にインターフェースを指定することで
// 必要なメソッドを実装していると判断する
func Print(stringer Stringer) {
	fmt.Println(stringer.String())
}
// 何も定義しないインターフェースを使うと
// どのような型も渡せるメソッドを作れる
func Do(e interface{}) {
	// do something
}
type StringStruct struct {
	Text string
}
func (ss *StringStruct) String() string {
	return ss.Text;
}
func NewStringStruct(text string) *StringStruct {
	return &StringStruct{
		Text: text,
	}
}
func RunInterface() {
	ss := NewStringStruct("インターフェース ---------- ")
	Print(ss)
}


//
// 型の埋め込み
// 継承の代わりになるもの
// 下記ではUserをUserTaskに埋め込む例
//
type User struct {
	FirstName string
	LastName string
}
func (u *User) FullName() string {
	fullname := fmt.Sprintf("%s %s", u.FirstName, u.LastName)
	return fullname
}
func NewUser(firstName, lastName string) *User {
	return &User{
		FirstName: firstName,
		LastName: lastName,
	}
}
type UserTask struct {
	ID int
	Detail string
	done bool
	*User // Userを埋め込む
}
func NewUserTask(id int, detail, firstName, lastName string) *UserTask {
	task := &UserTask {
		ID: id,
		Detail: detail,
		done: false,
		User: NewUser(firstName, lastName),
	}
	return task
}
func RunEmbed() {
	fmt.Println("型の埋め込み ---------- ")
	task := NewUserTask(1, "buy the milk", "Jxck", "Daniel")

	// UserTaskにUserのフィールドが埋め込まれている
	fmt.Println(task.FirstName)
	fmt.Println(task.LastName)

	// UserTaskにUserのメソッドが埋め込まれている
	fmt.Println(task.FullName())

	// UserTaskから埋め込まれたUser自体にもアクセス可能
	fmt.Println(task.User)
}


//
// 型の変換
//
func CastFunc() {
	// キャスト
	var i uint8 = 3
	var j uint32 = uint32(i) // uint8 -> uint32
	fmt.Println(j)

	var s string = "abc"
	var b []byte = []byte(s) // string -> []bytes
	fmt.Println(b)

	// キャストに失敗した場合はパニックが発生する
	// a := int("a")
}
func TypeAssertionFunc(value interface{}) {
	// TypeAssertion
	// 第1戻り値はその型に変換された値が返り、
	// 第2戻り値は成否を返す
        // (第2戻り値を指定しなかった場合はパニック起こる)
	s, ok := value.(string)
	if ok {
		fmt.Printf("value is string: %s\n", s)
	} else {
		fmt.Printf("value is not string\n")
	}
}
func TypeSwitchFunc(value interface{}) {
	switch v := value.(type) {
	case string:
		fmt.Printf("value is string: %s\n", v)
	case int:
		fmt.Printf("value is int: %d\n", v)
	case Stringer:
		fmt.Printf("value is Stringer: %s\n", v)
	}
}
func RunType() {
	fmt.Println("型の変換 ---------- ")
	CastFunc()
	TypeAssertionFunc("StringValue")
	TypeAssertionFunc(1)
	TypeSwitchFunc("StringValue!!")
	TypeSwitchFunc(10)
}

func main() {
	RunProcessTask()
	RunTask()
	RunFinish()
	RunNewTask()
	RunTaskFunc()
	RunInterface()
	RunEmbed()
	RunType()
}

チャネルにバッファを設けて処理ブロックを制御

package main

import (
	"fmt"
	"time"
)

func main() {
	// バッファを3として設定
	ch := make(chan string, 3)

	go func() {
		time.Sleep(time.Second)
		s := <-ch // 1秒後にデータを読み出す
		fmt.Printf("get %s\n", s)
	}()

	ch <- "a" // ブロックしない
	fmt.Println("put a")

	ch <- "b" // ブロックしない
	fmt.Println("put b")

	ch <- "c" // ブロックしない
	fmt.Println("put c")

	ch <- "d" // 1秒後にデータが読み出されるまでブロック
	fmt.Println("put d")
}

Goことはじめ2

第2章 基本文法―覚えやすいコンパクトな言語仕様:はじめてのGo―シンプルな言語仕様,型システム,並行処理|gihyo.jp … 技術評論社
より学んだことメモ。

基本的な文法について

package main

import (
	"fmt"
	"os"
	"errors"
	"log"
	// f "fmt" -> と記述すると f.Println()のようにアクセスできる
	// . "strings" -> と記述すると ToUpper('xx') とパッケージ指定なしでアクセスできる
)

//
// 代入処理について
//
func substitute() {
	fmt.Println("substitute -------------------- ")

	// 変数代入
	var message string = "hello world"
	fmt.Println(message)

	// 関数の中では型推論して代入もできる
	message2 := "hello world"
	fmt.Println(message2)

	// 定数定義
	const Hello string = "Hello Const"

	// 変数を宣言して明示的に初期化しなかった場合は
	// ゼロ値で初期化される
        // 整数型: 0
        // 浮動小数点型: 0.0
        // bool: false
        // string: ""
        // 配列:  各要素がゼロ値の配列
        // 構造体: 各フィールドがゼロ値の構造体
        // そのほかの型: nil

	const message3 string = `
	複数行に渡る
	文字列を使うときは
	バッククォートでくるる
	`
}

//
// 条件分岐・繰り返し
//
func repeat() {
	fmt.Println("repeat -------------------- ")

	// if文 Goでは丸かっこは不要
	a, b := 10, 100
	if a > b {
		fmt.Println("a is larger than b")
	} else if a < b {
		fmt.Println("a is smaller than b")
	} else {
		fmt.Println("a equals b")
	}

	// 繰り返しはfor文だけ
	n := 0
	for n < 10 {
		fmt.Printf("n = %d\n", n)
		n++
	}

	// 無限ループ・break・continue
	m := 0
	for {
		m++
		if m > 10 {
			break // ループを抜ける
		}
		if m%2 == 0 {
			continue // 偶数なら次の繰り返しに映る
		}
		fmt.Println(m) // 奇数のみ表示
	}

	// switch文
	// breakは書かなくていい
	p := 10
	switch p {
	case 15:
		fmt.Println("FizzBuzz")
	case 10:
		fmt.Println("Buzz")
	case 3, 6, 9:  // カンマ切りで複数指定可能
		fmt.Println("Fizz")

		// そのまま下に処理をおろしたい場合は
		// fallthrough
		// と記述する(逆break)
	default:
		fmt.Println(p)
	}

	// if文と同じようにかける
	q := 10
	switch {
	case (p % 15 == 0):
		fmt.Println("FizzBuzz")
	case (p % 5 == 0):
		fmt.Println("Buzz")
	default:
		fmt.Println(q)
	}
}

//
// 関数
//
// 引数の後に型を指定する
func sum1(i, j int) { // func sum(i int, j int) と同じ
	fmt.Println(i + j)
}

// 戻り値がある場合は引数の次に指定する
func sum2(i, j int) int {
	return i + j
}

// 関数は複数の値を返せる
func swap(i, j int) (int, int) {
	return j, i
}

// 内部で発生したエラーは戻り値で表現する
func errorFunc() {
	// _ で 第1戻り値を無視
	_, err := os.Open("sample.txt")
	if err != nil {
		// エラー処理
		fmt.Println("file open error")
	}
	fmt.Println("file open success")
}

// 自作のエラーはerrorsパッケージを用いて作ることができる
func div(i, j int) (int, error) {
	if j == 0 {
		// 自作のエラーを返す
		return 0, errors.New("divied by zero")
	}
	return i / j, nil
}

// 名前付き戻り値
// 関数内ではゼロ値で初期化された変数として扱われる
func divWithName(i, j int) (result int, err error) {
	if j == 0 {
		err = errors.New("divied by zero")
		return  // return 0, err と同じ
	}
	result = i / j
	return // return result, nil と同じ
}

// 関数はオブジェクト
func wrapFunc() {
	// 関数リテラル(無名関数)
	// 即時実行される
	func(i, j int) {
		fmt.Println(i + j)
	}(2, 4)

	// 関数は変数に代入できる
	var sum func(i, j int) = func(i, j int) {
		fmt.Println(i + j)
	}
	sum(2, 3)
}


//
// 配列
//
func arrayFunc() {
	fmt.Println("arrayFunc -------------------- ")

	// Goの配列は固定長
	var arr [4]string
	arr[0] = "a"
	arr[1] = "b"
	arr[2] = "c"
	arr[3] = "d"
	fmt.Println(arr[0])

	// 宣言と代入
	arr2 := [4]string{"a", "b", "c", "d"}
	fmt.Println(arr2)

	// 暗黙的なサイズ指定
	arr3 := [...]string{"a", "b", "c", "d"}
	fmt.Println(arr3)

	// 長さの違う配列は別の型
	// 関数に配列を渡す場合は"値渡し"になる
}

//
// スライス
// スライスは,可変長配列として扱うことができます。
// 配列を直接使うのは,シビアなメモリ管理が必要な一部のプログラムだけなので,
// 基本的にはスライスを用います。
//
func sliceFunc() {
	fmt.Println("sliceFunc -------------------- ")

	// スライスの型には長さの情報はない
	var s []string

	// 追加
	s = append(s, "a") // 追加した要素を返す
	s = append(s, "b")
	s = append(s, "c", "d")
	fmt.Println(s) // [a b c d]

	// 結合
	s1 := []string{"a", "b"}
	s2 := []string{"c", "d"}
	s1 = append(s1, s2...)  // s1にs2を追加
	fmt.Println(s1) // [a b c d]

	// 繰り返し処理
	// rangeは配列,スライス,string,マップに対して使うことができる
	s11 := []string{"a", "b", "c", "d"}
	for i, v := range s11 {
		// i = 添字, v = 値
		fmt.Println(i, v)
	}

	// 値の切り出し
	s21 := []int{1, 2, 3, 4, 5}
	fmt.Println(s21[2:4])      // [2 3]
	fmt.Println(s21[0:len(s)]) // [0 1 2 3 4 5]
	fmt.Println(s21[:3])       // [0 1 2]
	fmt.Println(s21[3:])       // [3 4 5]
	fmt.Println(s21[:])        // [0 1 2 3 4 5]

	// 可変長引数
	var _sum func(nums ...int) (result int) = func(nums ...int) (result int) {
		// numsは []int型
		for _, n := range nums {
			result += n
		}
		return
	}
	fmt.Println(_sum(1, 2, 3, 4)) // 10
}

//
// マップ
// マップは値をKey-Valueの対応で保存するデータ構造
//
func mapFunc() {
	fmt.Println("mapFunc -------------------- ")

	// 宣言 key=int, value=string
	var month map[int]string = map[int]string{}
	month[1] = "January"
	month[2] = "February"
	fmt.Println(month)

	// 宣言と初期化を一緒にする場合
	month2 := map[int]string {
		1: "January",
		2: "February",
	}
	fmt.Println(month2)

	// 値を取り出す
	jan := month[1]
	fmt.Println(jan)

	// マップにキーが存在するかチェック
	_, ok := month[1]
	if ok {
		fmt.Println("month[1] is present")
	}

	// 要素の削除
	delete(month, 1)

	// 繰り返し処理
	// 処理順番は保証されない
	for key, value := range month {
		fmt.Printf("%d %s\n", key, value)
	}
}

//
// ポインタ
// ポインタを使うことで参照渡しができる
//
func callByValue(i int) {
	i = 20; // 値を上書きする
}
func callByRef(i *int) {
	*i = 20; // 参照先を上書きする
}

//
// 関数を抜けるときに必ず実行
//
func deferFunc() {
	fmt.Println("deferFunc -------------------- ")

	file, err := os.Open("./error.go")
	if err != nil {
		fmt.Println("FileOpenError")
	}
	// 関数を抜ける前に必ず実行される
	defer file.Close()

	// 正常処理
	fmt.Println("deferFuncProcess")
}

//
// パニックと後処理
//
func panicFunc() {
	fmt.Println("PanicFunc -------------------- ")

	// 後処理
	defer func() {
		// パニックで発生したエラーはrecoverで取得できる
		err := recover()
		if err != nil {
			log.Print(err)
		}
	}()

	a := []int{1, 2, 3}
	fmt.Println(a[10]) // パニック発生

	// 自前でパニックを起こすこともできる
	// panic(errors.New("index out of range"))
}

func main() {
	substitute()
	repeat()

	fmt.Println("Function -------------------- ")
	sum1(1, 2)
	s := sum2(2, 3)
	fmt.Println(s)

	x, y := swap(3, 4)
	fmt.Println(x, y)

	errorFunc()
	_, err := div(10, 0)
	if err != nil {
		log.Print(err)
		// Fatalを使用するとステータス=1で終了する
		// log.Fatal(err)
	}
	m, err := divWithName(10, 2)
	fmt.Println(m)
	wrapFunc()

	arrayFunc()
	sliceFunc()
	mapFunc()

	fmt.Println("Pointer -------------------- ")
	var i int = 10;
	callByValue(i) // 値渡し
	fmt.Println(i) // 10
	callByRef(&i)  // 参照渡し
	fmt.Println(i) // 20

	deferFunc()
	panicFunc()
}

シェルのtestコマンド

シェルのtestコマンドの理解が怪しかったので、使い方をメモしておく。

#!bin/sh

# $?==0 で正常終了

# 数値の比較
## 1 == 1
test 1 -eq 1; echo $?

## 1 != 2
test 1 -ne 2; echo $?

## 1 < 2
test 1 -lt 2; echo $?

## 2 > 1
test 2 -gt 1; echo $?

## 1 <= 1
test 1 -le 1; echo $?

## 1 >= 1
test 1 -ge 1; echo $?


# 文字列の比較
## "abc" == "abc"
test "abc" = "abc"; echo $?

## "abc" != "aaa"
test "abc" != "aaa"; echo $?


# 空チェック
## 変数に値が入っているか
test -n HOGE; echo $?

## 変数が空か
test -z HOGE; echo $?


# ファイルチェック
## file2が新しいか
touch file1
touch file2
test ./file1 -ot ./file2

## fileが存在するか
touch file3
test -f ./file3; echo $?

## fileが存在しない
test ! -f ./file4; echo $?

## ディレクトリが存在するか
mkdir dir1
test -d ./dir1; echo $?


# 略式 [ ]
# [ は testコマンド
# ] は [を使うためのオプション
[ 1 -lt 2 ]; echo $?


# AND条件 OR条件
[ 1 -eq 1 ] && [ 1 -lt 2 ] || [ 2 -eq 2 ]; echo $?


# if文
## 一般的な書き方
if [ 1 -eq 1 ] && [ 1 -lt 2 ] || [ 2 -eq 2 ]; then
  echo "if文の中の実行"
fi

## これでもOK
if [ 1 -eq 1 ] && [ 1 -lt 2 ] || [ 2 -eq 2 ]
then
  echo "if文の中の実行"
fi

Goことはじめ

http://gihyo.jp/dev/feature/01/go_4beginners で学んだことをメモしていく。

はじめに

# インストール
brew install go

# ./bash_profileの設定
export GOROOT=/usr/local/opt/go/libexec
export GOPATH=$HOME
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

# ソースコードから実行
go run hello.go

# コンパイルして実行
go build hello.go
./hello

# コーディング規約に合わせてフォーマット
go fmt hello.go

# パッケージ(ここではfmt)のドキュメントを表示
go doc fmt

プロジェクトを作る

# プロジェクトディレクトリ基本形
# Goのコマンドは,このGOPATHとその下にある先の3つのディレクトリの命名規則を用いて,Makefileなどの構成ファイルは一切なしで,依存関係を解決してビルドできるようになっている。
tree
hello/
├── bin
├── pkg
└── src

# プロジェクトディレクトリにパスを通す
cd hello
export GOPATH=`pwd` # helloをGOPATHに登録

# ソースを書く1
cat src/hello/hello.go
# ---
package hello

var Message string = "hello world"

# ソースを書く2
cat src/main/main.go
# ---
package main

import (
    "fmt"
    "hello"
)

func main() {
    fmt.Println(hello.Message) // hello world
}

# 実行してみる
cd $GOPATH/src/main
go run main.go
hello world

# 実行ファイルをbin以下に作る
cd $GOPATH/src/main
go install

# binにパスを通しておくと、すぐに実行できて便利
export PATH=$PATH:$GOPATH/bin
main
hello world