概要
A Tour of Goの順番に沿ってGoの基本で個人的に学習したことをまとめています。
No | 記事 |
---|---|
1 | 【Go】基本文法①(基礎) |
2 | 【Go】基本文法②(フロー制御文) |
3 | 〜〜【Go】基本文法③(ポインタ・構造体)「今ココ」〜〜 |
4 | 【Go】基本文法④(配列・スライス) |
5 | 【Go】基本文法⑤(Maps・ Range) |
6 | 【Go】基本文法⑥(インターフェース) |
7 | 【Go】基本文法⑦(並行処理) |
8 | 【Go】基本文法総まとめ |
今回はポインタと構造体に焦点を当てて学習しました。
ポインタ
ポインタとは?
ポインタはメモリのアドレス情報のことです。
詳しい説明は以下のリンクがとても参考になりました。
【参考】
package main
import "fmt"
func main() {
var var1 int = 10
var var2 *int = &var1
fmt.Println(var1) //=> 10
fmt.Println(var2) //=> 0x10414020
fmt.Println(*var2) //=> 10
}
変数のアドレス取得方法
Goでは&
を用いることで変数のアドレスの取得が可能です。
例えば &var1
で変数 var1
のアドレスを取得することが可能です。
func main() {
var var1 int = 10
var var2 *int = &var1
fmt.Println(var1) //=> 10
fmt.Println(var2) //=> 0x10414020
}
上記では変数 var1
のアドレスを ポインタ型変数var2
に入れてその値(0x10414020)を表示しています。
次にポインタ型変数とは何か理解します。
ポインタ型とは?
メモリー上のアドレスを記憶する変数の型のこと です。
サンプルコード上の *int
がポインタ型を示します。
var var2 *int = &var1
ポインタ型変数とは?
ポインタ型で宣言された変数のこと です。
つまり、メモリ上のアドレスを値として入れられる変数のこと です。
ポインタ型にしたい変数に *
をつけて宣言します。
var var1 int //int型
var var2 *int //int型へのポイント型
サンプルコード上の var2
がポインタ型変数を示します。
初期値が指定されていない場合、Go 言語のポインタは nil (nil ポインタ)
に初期化されます。
【参考】ポインタ型変数とは
ポインタ型変数の中身へのアクセス方法
ポインタ型変数名の前に *
をつけることで変数の中身へのアクセスが可能です。
例えば *var2
とすることで var2
の値の参照が可能です。
func main() {
var var1 int = 10
var var2 *int = &var1
fmt.Println(*var2) //=> 10
}
Structs(構造体)
構造体とは?
Goにはオブジェクト指向言語におけるclassというものは存在しません。
似た役割として関連する情報をひとまとめにする struct(構造体)
が使用されます。
構造体の定義方法
構造体は下記のように type
と struct
を使用して定義します。
package main
import "fmt"
type Person struct {
firstName string
age int
}
構造体の初期化方法
構造体の初期化方法は複数存在します。
- ①変数定義後にフィールドを設定する方法
- ②
{}
で順番にフィールドの値を渡す方法 - ③フィールド名を
:
で指定する方法
上から順に初期化の方法を確認します。
①変数定義後にフィールドを設定する方法
type Person struct {
firstName string
age int
}
func main(){
var mike Person
mike.firstName = "Mike"
mike.age = 20
fmt.Println(mike.firstName, mike.age) //=> Mike 20
}
②{}
で順番にフィールドの値を渡す方法
type Person struct {
firstName string
age int
}
func main(){
bob := Person{"Bob", 30}
fmt.Println(bob.firstName, bob.age) //=>Bob 30
}
③フィールド名を :
で指定する方法
type Person struct {
firstName string
age int
}
func main(){
sam := Person{age: 15, firstName: "Sam"}
fmt.Println(sam.firstName, sam.age) //=>Sam 15
}
また以下のように初期化関数を作成することで初期化をすることも一般的に行われます。
type Person struct {
firstName string
age int
}
func newPerson(firstName string, age int) *Person{
person := new(Person)
person.firstName = firstName
person.age = age
return person
}
func main(){
var jen *Person = newPerson("Jennifer", 40)
fmt.Println(jen.firstName, jen.age) //=>Jennifer 40
}
構造体とポインタ
struct
のフィールドは、struct
のポインタを通してアクセスすることもできます。
package main
import "fmt"
type Person struct {
firstName string
age int
}
func main() {
tim := Person{"Tim", 25}
person1 := &tim
(*person1).age = 25
person1.age = 53 //shortcutでp.Xと書くことも出来る
fmt.Println(person1) //=> {Tim 53}
}
構造体でのメソッドの定義
Goにはクラスと言う概念は存在しませんが、構造体内にメソッド method
を定義できます。
普通の関数と違うのはレシーバ引数の部分だけです。
メソッドは以下の様に定義することができます。
func (<レシーバ引数>) <関数名>([引数]) [戻り値の型] {
[関数の本体]
}
実際に Person
という構造体に対して intro
というメソッドを定義してみます。
type Person struct {
firstName string
age int
}
func (p Person) intro(greetings string) string{
return greetings + " I am " + p.firstName
}
func main(){
bob := Person{"Bob", 30}
fmt.Println(bob.intro("Hello")) //=> Hello I am Bob
}
上記の例では intro
メソッドは p
という名前の Person
型のレシーバを持つことを意味しています。
構造体の埋め込み
上記で何度も記した通り、Goはオブジェクト指向言語の様なクラスを持ちません。
ですのでクラスの継承も存在しません。
そこで継承に似た機能として構造体の埋め込みがあります。
package main
import "fmt"
type Person struct {
firstName string
}
func (a Person) name() string{ //Personのメソッド
return a.firstName
}
type User struct {
Person
}
func (a User) name() string { //Userのメソッド
return a.firstName
}
func main(){
bob := Person{"Bob"}
mike := User{}
mike.firstName = "Mike"
fmt.Println(bob.name()) //=> Bob
fmt.Println(mike.name()) //=> Mike
}
参考
My Jorney of Go③
C言語のポインタきらい
Goで学ぶポインタとアドレス
メソッドの定義方法
ポインタ型変数とは
Goのinterface/structの埋め込み
お気楽 Go 言語プログラミング入門