Open7

Goのおべんきょ

motty93motty93

構造体・ポインタ・関数を組み合わせたコードをいい加減頭にたたきこむ

motty93motty93

関数と構造体を使ったオブジェクト指向的な設計が以下

package main

import (
	"fmt"
	"time"
)

type Book struct {
	title    string
	author   string
	numPages int

	isSaved bool
	savedAt time.Time
}

func (b *Book) struct {
	b.isSaved = true
	b.savedAt = time.Now()
}

func main() {
	book := Book{
		title:    "The Hobbit",
		author:   "J.R.R. Tolkien",
		numPages: 310,
	}

	book.save()
	fmt.Println("Book saved at:", book.savedAt)
}
motty93motty93

構造体を関数に渡す方法はあまり使われない

func saveBook(b *Book) {
	b.title = "The Hobbit"
	b.author = "J.R.R. Tolkien"
	b.numPages = 310
	b.isSaved = true
	b.savedAt = time.Now()
}

book2 := Book{}
saveBook(&book2)
fmt.Println("Book2 saved at:", book2.savedAt)

book3 := &Book{}
saveBook(book3)
fmt.Println("NoSaveBook saved at:", book3.savedAt)

更に言えば値渡しだとメモリの無駄になってしまう可能性が高い。

motty93motty93

上記を使うパターン

  • ビジネスロジックをメソッドから分離したい場合
    • 特に異なる構造体にまたがって操作が必要な場合に使う
  • 構造体自体を変更できない、または、したくない場合
    • 外部パッケージの構造体とか特に
  • ユーティリティ関数として提供する場合
    • 単純な変換やデータの初期化処理など、複数の構造体インスタンスに適用される共通処理を外部関数として提供したいとき
func initializeBook(b *Book) {
.
.
.
}

使いとしたらこんなの。

motty93motty93
type User struct {
    name string
}

func main () {
    users := map[int]*User{}
    users2 := map[int]User{}
}

users, users2の違いについて。

motty93motty93
  1. users := map[int]*User{}
    usersはキーがint, 値が*User(ポインタ)型のmap
    このmapに格納されるUserはポインタ型なので、User構造体の内容を直接更新できる。
users[0] = &User{name: "motty"}
users[0].name = "ahoMotty"
motty93motty93
  1. users2 := map[int]User{}
    users2はキーがint, 値が User(値型)のmap
    mapに格納されるUseは値型なので、構造体全体がコピーされる。User構造体を直接更新することはできない(いわゆるreadonly)。
    変更したい場合はmapから取り出して更新し、再びmapに格納する必要がある。
// 不可能
// users2[0] = User{name: "motty"}

u := users2[0]
u.name = "motty"
users2[0] = u