コピペコードで快適生活

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

Goことはじめ(ファイルのRead/Write)

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

package main

import (
	"fmt"
	"log"
	"os"
)

//
// ファイルの書き込み
//
func FileWriteFunc() {
	fmt.Println("ファイルの書き込み --------- ")

	// ファイルを生成
	file, err := os.Create("./file.txt")
	if err != nil {
		log.Fatal(err)
	}

	// 終了時にファイルを閉じる
	defer file.Close()

	// 書き込むデータを[]byteで用意する
	message := []byte("hello world\n")

	// Write()を用いて書き込む
	_, err = file.Write(message)
	if err != nil { // エラー処理
		 log.Fatal(err)
	}

	// 直接文字列を渡す版1
	// _, err = file.WriteString("hello world\n")

	// 直接文字列を渡す版2
	// _, err = fmt.Fprint(file, "hello world\n")
}

//
// ファイルの読み込み
//
func FileReadFunc() {
	fmt.Println("ファイルの読み込み --------- ")

	// ファイルを開く
	file, err := os.Open("./file.txt")
	if err != nil { // エラー処理
		log.Fatal(err)
	}

	// プログラムが終わったらファイルを閉じる
	defer file.Close()

	// 12byte格納可能なスライスを用意する
	message := make([]byte, 12)

	// ファイル内のデータをスライスに読み出す
	// io.Reader インターフェースを使う
        // type Reader interface {
        //     Read(p []byte) (n int, err error)
        // }
	_, err = file.Read(message)
	if err != nil {
		log.Fatal(err)
	}

	// ファイルの中身をすべて読み出す
	// ioutil.ReadAllを使えば、事前にbyte列を準備する必要はない
	// file, _ := os.Open("./file.txt")
	// message, err := ioutil.ReadAll(file)

	// 文字列にして表示
	fmt.Print(string(message))
}

func main() {
	FileWriteFunc()
	FileReadFunc()
}

JSONのEncoder/Decoder経由の保存

package main

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

type Person struct {
	ID int `json:"id"`
	Name string `json:"name"`
	Email string `json:"-"`
	Age int `json:"age"`
	Address string `json:"address,omitempty"`
	memo string
}

//
// JSONの書き出し
//
func JsonWriteFunc() {
	fmt.Println("JSONの書き出し ---------- ")

	person := &Person{
		ID: 1,
		Name: "Hogeo",
		Email: "hogeo@example.com",
		Age: 20,
		Address: "",
		memo: "TestUser",
	}

	// ファイルを開く
	file, err := os.Create("./person.json")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	// エンコーダの取得
	encoder := json.NewEncoder(file)

	// JSONエンコードしたデータの書き込み
	// byte[]に変換しなくても直接構造体を渡せる
	err = encoder.Encode(person)
	if err != nil {
		log.Fatal(err)
	}
}

//
// JSONの読み込み
//
func JsonReadFunc() {
	fmt.Println("JSONの読み込み ---------- ")

	// ファイルを開く
	file, err := os.Open("./person.json")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	// データを書き込む変数
	var person Person

	// デコーダの取得
	decoder := json.NewDecoder(file)

	// JSONデコードしたデータの読み込み
	// JSONフォーマットに誤りがあればエラー
	// 構造体にないフィールドは無視される
	err = decoder.Decode(&person)
	if err != nil {
		log.Fatal(err)
	}

	// 読み出した結果の表示
	fmt.Println(person)
}

func main() {
	JsonWriteFunc()
	JsonReadFunc()
}

ioutls使うと便利

http://gihyo.jp/dev/feature/01/go_4beginners/0004?page=3

package main

import (
	"fmt"
	"io/ioutil"
	"log"
)

//
// ファイルの操作は、
// io/ioutilsパッケージを使うとより簡単にできる
//
func main() {
	hello := []byte("hello world\n")

	// ファイルにメッセージを書き込む
	// 第2引数にバイト列、第3引数にパーミッション
	err := ioutil.WriteFile("./file.txt", hello, 0666)
	if err != nil {
		log.Fatal(err)
	}

	// ファイルの中身を全て読みだす
	message, err := ioutil.ReadFile("./file.txt")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Print(string(message))
}

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")
}