はじめに
今回はGoの基本文法である「ポインタ・構造体・配列」についてです。
目次
Pointers : ポインタ
ポインタとは、値のメモリアドレスのことです。
変数の型の前に*が付くものはポインタ型変数、付かないものは変数となります。
var 変数名 *型
変数には格納されている値とは別にアドレス情報を持っています。いわば変数の住所ですね。
Goでは&を使って、変数のアドレスを取得することができます。
package main
import "fmt"
func main() {
// string 型の変数 str
var str string = "ポインタのテスト"
// string 型へのポインタ型 str_pointer 変数に str のアドレスを格納
var str_pointer *string = &str
fmt.Println(str) // => ポインタのテスト
fmt.Println(str_pointer) // => 0x000096210
}
ポインタ型変数名の前に*をつければ、変数の値を取得することができます。
*をつければアドレス、つけなければ値へのアクセスとなります。
fmt.Println(*str_pointer) // => ポインタのテスト
主な用途は、引数やレシーバを経由する関数内で書き換えたい時です。
Goでは、書き換え対象はポインタとして渡す必要があります。
package main
import "fmt"
type Pointer struct{ value int }
// ポインタ型でないため、+5されない(書き換え不可)
func (h Pointer) Not_Pointer(v int) {
h.value = v + 5
}
// ポインタ型のため、+5される(書き換え可)
func (h *Pointer) Pointer(v int) {
h.value = v + 5
}
func main() {
var h Pointer // データ書き換え対象の変数
h.Not_Pointer(0)
fmt.Printf("Not_Pointer:%v\n", h.value) // => Not_Pointer:0
h.Pointer(0)
fmt.Printf("Pointer:%v\n", h.value) // => Pointer:5
}
Structs : 構造体
Goにクラスは存在しません。
構造体はクラスと似た役割を果たし、関連情報をひとまとめにすることができます。
構造体は、typeとstructを使って定義(個別・複数どちらでも定義可)します。
構造体はフィールドの集まりです。
type 構造体名 struct {
フィールド名 型
フィールド名 型
}
フィールドへは.を使ってアクセスします。
構造体のポインタ名.構造体のフィールド名 = 1
構造体の初期化方法は複数あります。
①変数定義後にフィールドを設定する方法
②{}内で順番にフィールドの値を渡す方法
③フィールド名を:で指定する方法
// ①
type People struct {
name string
age int
}
func main(){
var jack People
jack.name = "Jack"
jack.age = 20
fmt.Println(jack.name, jack.age) // => Jack 20
}
// ②
func main(){
jack := People{"Jack", 20}
fmt.Println(jack.name, jack.age) // => Jack 20
}
// ③
func main(){
jack := People{age: 20, name: "Jack"}
fmt.Println(jack.name, jack.age) // => Jack 20
}
以下のように、初期化関数を作成し初期化することも一般的のようです。
func newPerson(name string, age int) *People{
person := new(People) // 初期化する
person.name = name // name フィールドへ値を代入
person.age = age // age フィールドへ値を代入
return person
}
func main(){
var jack *People = newPerson("Jack", 20)
fmt.Println(jack.name, jack.age) // => Jack 20
}
Goにはクラスの概念がないですが、構造体内でメソッドを定義することができます。
メソッドの定義方法は以下の通りです。関数と異なる点はレシーバ引数の部分だけです。
func (レシーバ引数) 関数名(引数) 戻り値の型 {
関数の本体
}
package main
import "fmt"
type People struct {
name string
age int
}
// メソッド定義 : Poeple という構造体に対して introduction というメソッドを定義
// introduction メソッドは p という名前の People 型のレシーバを持つ
func (p People) introduction(greetings string) string{
return greetings + " I am " + p.name
}
func main(){
jack := People{"Jack", 20}
fmt.Println(jack.introduction("Hello")) // => Hello I am Jack
}
Embedded Structs : 構造体の埋め込み(継承)
他の言語にあるクラス継承に似た機能として構造体の埋め込みがあります。
1つの構造体を別の構造体へ埋め込むことが可能です。
package main
import "fmt"
// 構造体宣言
type character struct {
name string
age int
}
func main() {
// 構造体へデータセット
c := character{
name: "Jack",
age: 20,
}
// 構造体自体を出力
fmt.Println(c) // => {Jack 20}
// 構造体のフィールドデータを出力
fmt.Println(c.name, c.age) // => Jack 20
}
Arrays : 配列
配列は、同じ型を持つ値(要素)を並べたものです。
Goにおける配列は固定長配列のため、最初に宣言した配列サイズは変更できません。
配列の宣言方法は以下の通りです。
① var 変数名 [長さ]型
② var 変数名 [長さ]型 = [大きさ]型{初期値1, 初期値n}
③ 変数名 := [...]型{初期値1, 初期値n}
// ①
func main(){
var arr[2] string
arr[0] = "Hello World"
arr[1] = "Go"
fmt.Println(arr[0], arr[1]) //=> Hello World
fmt.Println(arr) //=> [Hello World]
}
// ②
func main(){
var arr[2] string = [2]string {"Hello", "Go"}
fmt.Println(arr[0], arr[1]) //=> Hello Go
fmt.Println(arr) //=> [Hello Go]
}
// ③
// 要素数は省略可、要素数は自動カウントしている
func main(){
arr := [...] string{"Hello", "Go"}
fmt.Println(arr[0], arr[1]) //=> Hello Go}
fmt.Println(arr) //=> [Hello Go]
}
参考文献
A Tour of Go
Goで学ぶポインタとアドレス
Go言語(golang) 構造体の定義と使い方
[Go]構造体を学ぶ
Go 言語の配列