Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@R_R

Go 言語仕様9(構造体)

概要

Go 言語の仕様まとめ。

前回:
Go 言語仕様8(ポインタ)

内容

  • 構造体
    • 宣言・代入
    • ポインタ
    • メソッド
    • 多重構造体
    • スライスとの合せ技

構造体

  • 宣言方法

構造体では、複数の任意の型を一つにまとめることができる。

宣言・代入
// 複数の任意の型を一つにまとめることができる
type Structure struct {
    // 外部パッケージがら呼び出せるように、先頭一文字は大文字にしておく
    Amount   int
    Language string
    Decimal  float64
    Bl       bool
}

func main() {
    // 変数の宣言方法と同じ
    var st Structure
    st2 := Structure{}
    // 各型の初期値が出力されることを確認
    fmt.Println(st) // {0  0 false}
    fmt.Println(st2) // {0  0 false}

    // 値を代入(.で各フィールドにアクセスできる)
    st.Amount = 1000
    st.Language = "Golang"
    fmt.Println(st.Amount, st.Language) // 1000 Golang

    // 初期値を指定して宣言
    st3 := Structure{
        Amount:   2000,
        Language: "Java",
        Decimal:  1.234,
        Bl:       true,
    }
    fmt.Println(st3) // {2000 Java 1.234 true}

    // 構造体のフィールドの順番で値のみを入れることも可能
    st4 := Structure{3000, "Python", 3.14, false}
    fmt.Println(st4)

    // 全フィールド分代入する必要がある
    st5 := Structure{3000, "Python", 3.14} // too few values in struct literal
}

  

  • ポインタ

構造体は値型のため、関数へ引数で渡したときなどは、元の構造体の値に影響がない。

値渡し
type Structure struct {
    Amount   int
    Language string
}

func Modify(st Structure) {
    st.Amount = 9999
    st.Language = "Golang"
}

func main() {
    var st Structure
    Modify(st)
    fmt.Println(st) // {0 }
}

そのため、ポインタ変数を作り、関数へ参照渡しする。

参照渡し
type Structure struct {
    Amount   int
    Language string
}

func Modify(st Structure) {
    st.Amount = 9999
    st.Language = "Golang"
}

func Modify2(st *Structure) {
    st.Amount = 9999
    st.Language = "Golang"
}

func main() {
    var st Structure
    Modify(st)
    fmt.Println(st)

    // 構造体のポインタを明示的に作る方法が推奨パターン
    st2 := &Structure{}
    Modify2(st2)
    fmt.Println(*st2) // {9999 Golang}

    // 非推奨パターンA
    st3 := Structure{}
    Modify2(&st3)

    // 非推奨パターンB
    st4 := new(Structure)
    Modify2(st4)
}

  

  • メソッド

 メソッド:
  構造体に紐付く処理群。紐付けた構造体でのみ使用可能。

 関数:
  構造体に紐付かない処理群。

 レシーバ:
  メソッドと紐付いた構造体。

関数を使った構造体の値更新
type Structure struct {
    Amount   int
    Language string
}

func Modify(st *Structure) {
    st.Amount = 2000
}

func main() {
    // 関数を使った構造体の値更新
    st := &Structure{100, "Golang"}
    Modify(st)
    fmt.Println(st) // &{2000 Golang}
}
メソッドを使った構造体の値更新
type Structure struct {
    Amount   int
    Language string
}

// メソッドのレシーバーはポインタ型にするのが一般的
func (st *Structure) Modify() {
    // レシーバーの値を書き換える
    st.Amount = 3000
}

func main() {
    st := &Structure{100, "Golang"}

    // レシーバー.メソッドで呼び出し
    st.Modify()
    fmt.Println(st) // &{3000 Golang}
}

  

  • 多重構造体

親子関係のような感じで、構造体を構造体のフィールドとして定義できる。

多重構造体
type SubStructure1 struct {
    Amount   int
    Language string
}

type SubStructure2 struct {
    Decimal float64
    Bl      bool
}

// 構造体をフィールドで持てる
type Structure struct {
    SubStructure1 SubStructure1
    // フィールド名が同じであれば、型宣言は省略可能
    SubStructure2
}

// メソッド
func (subst *SubStructure1) Modify() {
    subst.Amount = 9000
    subst.Language = "Java"
}

func main() {
    // 子の構造体にアクセスできる
    st2 := Structure{}
    fmt.Println(st2) // {{0 } {0 false}}

    // 値を入れる
    st2.SubStructure1.Amount = 100
    st2.SubStructure1.Language = "Golang"
    // 型宣言を省略した場合は、子の構造体に直接アクセス可能
    st2.Decimal = 1.234
    st2.Bl = true
    fmt.Println(st2) // {{100 Golang} {1.234 true}}

    // 値を入れつつ宣言
    st3 := Structure{
        SubStructure1: SubStructure1{
            Amount:   8000,
            Language: "Golang",
        },
    }
    fmt.Println(st3) // {{8000 Golang} {0 false}}

    // 親の構造体からこの構造体のメソッドを呼び出せる
    st2.SubStructure1.Modify()
    fmt.Println(st2)
}

  

  • スライスとの合せ技

構造体をスライスで扱える。

type Structure struct {
    Amount   int
    Language string
}

// 子の構造体をスライスでフィールドに持つ構造体
type SliceStruct struct {
    Structure []*Structure
}

func main() {
    // スライスで構造体を定義できる
    sl := make([]Structure, 3)
    fmt.Println(sl) // [{0 } {0 } {0 }]

    // 各スライスに値を代入
    sl[0].Amount = 100
    sl[1].Language = "Golang"
    sl[2].Amount = 200
    fmt.Println(sl) // [{100 } {0 Golang} {200 }]

    // スライスの構造体を定義して、
    v := Structure{100, "Galang"}
    v2 := Structure{100, "Java"}
    v3 := Structure{100, "Python"}
    // appendする
    slst := SliceStruct{}
    slst.Structure = append(slst.Structure, &v, &v2, &v3)
    // forで値を取り出す
    for _, v := range slst.Structure {
        fmt.Println(v)
    }
}

次回

Go 言語仕様10(テスト)

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
R_R

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?