Open7
Goのおべんきょ
構造体・ポインタ・関数を組み合わせたコードをいい加減頭にたたきこむ
関数と構造体を使ったオブジェクト指向的な設計が以下
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)
}
構造体を関数に渡す方法はあまり使われない
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)
更に言えば値渡しだとメモリの無駄になってしまう可能性が高い。
上記を使うパターン
- ビジネスロジックをメソッドから分離したい場合
- 特に異なる構造体にまたがって操作が必要な場合に使う
- 構造体自体を変更できない、または、したくない場合
- 外部パッケージの構造体とか特に
- ユーティリティ関数として提供する場合
- 単純な変換やデータの初期化処理など、複数の構造体インスタンスに適用される共通処理を外部関数として提供したいとき
func initializeBook(b *Book) {
.
.
.
}
使いとしたらこんなの。
type User struct {
name string
}
func main () {
users := map[int]*User{}
users2 := map[int]User{}
}
users, users2の違いについて。
-
users := map[int]*User{}
usersはキーがint
, 値が*User
(ポインタ)型のmap
。
このmapに格納されるUserはポインタ型なので、User構造体の内容を直接更新できる。
例
users[0] = &User{name: "motty"}
users[0].name = "ahoMotty"
-
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