【Go入門】structとポインタ

Go
スポンサーリンク

Go言語のポインタに関連して、structについて見て行きたいと思います。

structとの関連についてはすでに少しだけですが「new()とポインタ」のところで触れました。

ここではもう少しstructとポインタについて見ておこうと思います。

スポンサーリンク

struct型の確認

structについて一度確認してみましょう。

package main

import "fmt"

type example struct {
	a int
	b int
	c string
}

func main() {

	e1 := example{
		a: 10,
		b: 100,
		c: "golang",
	}
	fmt.Println(e1)
	fmt.Println(e1.a, e1.b, e1.c)
	e1.a = 20
	fmt.Println(e1.a, e1.b, e1.c)

	e2 := example{a: 100}
	fmt.Println(e2)

	e3 := example{100, 200, "Programming"}
	fmt.Println(e3)

}

typeを使ってstructの新しい型のexampleを定義しています。

これをmain()関数の中でフィールド名を指定して値を割り当てて、Printin()で出力しています。

e1.aでフィールド名にアクセスして値を20に書き換えることができます。

e2、e3はフィールド名を指定せずに値を割り当てています。

実行すると次のようになります。

{10 100 golang}
10 100 golang
20 100 golang
{100 0 }
{100 200 Programming}

変数そのままを出力すると{}で囲まれて表示されます。フィールド名にアクセスして値を表示、値の変更ができています。

e2、e3の出力を比較するとわかりますが、値を入れていないe2の方は、int型のところは0、string型のところは空が表示されています。

スポンサーリンク

structとポインタ

上のコードを以下のように修正して、structとポインタを確認してみましょう。

package main

import "fmt"

type example struct {
	a int
	b int
	c string
}

func main() {

	e4 := example{}
	fmt.Println(e4)
	fmt.Printf("%T %v\n", e4, e4)

	var e5 example
	fmt.Println(e5)
	fmt.Printf("%T %v\n", e5, e5)

	e6 := new(example)
	fmt.Println(e6)
	fmt.Printf("%T %v\n", e6, e6)

	e7 := &example{}
	fmt.Println(e7)
	fmt.Printf("%T %v\n", e7, e7)

}

e4、e5は値を割り当てずにexample型を初期化して値と型を出力しています。e4は省略宣言、e5はvarで型宣言しています。

e6、e7はそれぞれnew()、&を使って値を割り当てずにexample型を初期化しています。

これはこちらで扱った内容と同じです。

実行すると、次のように表示されます。

{0 0 }
main.example {0 0 }
{0 0 }
main.example {0 0 }
&{0 0 }
*main.example &{0 0 }
&{0 0 }
*main.example &{0 0 }

e4とe5が同じことを意味し、e6とe7が同じことを意味しているのがわかります。

e6、e7の出力が、&、*がついているのでアドレス、ポインタ型となっているのが理解できます。

こうい書き方と意味の違いを理解しておくといいでしょう。また、e6とe7は同じ意味の表現でも、e7は&enampe{}と&を付けているので、ポインタ型と見ただけでわかるという利点があります。

今度は、次のように関数の引数の利用での違いを見てみましょう。

上のコードを下記のように修正してみます。

package main

import "fmt"

type example struct {
	a int
	b int
	c string
}

func changeEx(e example) {
	e.a = 1000
}

func changeEx2(e *example) {
	e.a = 1000
	// (*e).a = 1000 が厳密な書き方ですが、同じ意味として処理されます。
}

func main() {

	e8 := example{10, 100, "GOLANG"}
	changeEx(e8)
	fmt.Println(e8)

	e9 := &example{10, 100, "GOLANG"}
	changeEx2(e9)
	fmt.Println(e9)

}

2つの似たような関数を定義しています。引数にstructのexample型を渡す関数で、フィールドのひとつの値を変更する処理になっています。

下側の関数の引数は、ポインタ型のstructを渡しているという違いになっています。

これを、main()関数の中で値を渡して処理をして、それぞれ出力しています。

それぞれ同じ値を渡していますが、e9の方は引数をポインタ型にしています。

出力するとこうなります。

{10 100 GOLANG}
&{1000 100 GOLANG}

上側は処理をしても、アドレスに格納された値が変更されているわけでは無いので、関数の処理で値に変化はありません。

下側は、アドレスとして出力され、値も関数の処理が反映されているのがわかります。

スポンサーリンク

最後に

ここでは、Go言語のポインタについて、structとの関連を見てきました。

new()を使った方法と、&を使った方法で同じことを表現することができますが、&を使った方法の方が、コードの意味をポインタ型として理解しやすいという利点があります。

Go
スポンサーリンク
CodeGraffitiをフォローする

タイトルとURLをコピーしました