Help us understand the problem. What is going on with this article?

Go言語を真剣に勉強してみた〜基本構文編④(ポインタ、構造体)〜

More than 1 year has passed since last update.

はじめに

こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。:relaxed:
さて今回は「Go言語を真剣に勉強してみた〜基本構文編〜」の4回目と言うことで「ポインタと構造体」について見ていきましょう。
オブジェクト指向で育ってきた僕が一番理解に苦しんだ「ポインタ、構造体」です。
まだ、ポインタ、構造体について理解が追いついてない部分があるとは思いますが、最後までお付き合いください。
では、早速いってみましょう:point_up:

「Go言語を真剣に勉強してみた〜基本構文編①(変数、定数、条件分岐、繰り返し処理)〜」についてはこちらから。
「Go言語を真剣に勉強してみた〜基本構文編②(配列)〜」についてはこちらから。
「Go言語を真剣に勉強してみた〜基本構文編③(関数)〜」についてはこちらから。

ポインタ

PHP、JavaScript、Python、などを触っていると扱うことのないポインタですが、Go言語ではそれを扱うことができます。

今回はいきなりですが例をみてください。
例をみながら解説していきます。

// 普通、int型は以下のように定義しますが、
var n int = 100

// ポインタを扱う場合には、「*int」という表現で定義します.
var pointer *int

// &(アドレス演算子)を使うと、その変数のアドレスにアクセスできます.
// ここでは変数nのアドレスを、pointer変数に格納しています.
// (つまり、変数nと変数pointerは同じアドレスを参照するようにしました)
pointer = &n

// 同じアドレスを参照していることを確認できます.
fmt.Println("nのアドレス:", &n)           // nのアドレス: 0x10410020
fmt.Println("pointerの値:", pointer)     // pointerの値: 0x10410020

構造体

Goには他のオブジェクト指向言語におけるclassというものは存在しません。
なので、多様なデータ構造を一つの型として取り扱うことができるすなわち、複数の型の値を一つにまとめるものです。

定義

構造体は下記のように「struct」を使用して定義します。
*Goの場合、大文字から始まる名前は、他のパッケージからアクセス可能となります。
一方、小文字で始まる名前の場合、他のパッケージからアクセス不可能です(カプセル化)。同じパッケージ内であれば小文字でもアクセス可能です。

type 構造体名 struct {
   フィールド名 データ型
}

以下構造体の例

type User struct {
    email string //カプセル化
    Name string
    Age int
} 

構造体にアクセスする

var u User
u.Name = "taro"
u.Age = 30

初期化

構造体の初期化方法は複数あります。
1.変数定義後にフィールドを設定する方法

var u User
u.Name = "taro"
u.Age = 30

2.{}で順番にフィールドの値を渡す方法

u2 := User{"taro", 30}

3.フィールド名を:で指定する方法

u3 := User{Name: "taro", Age: 30}

また、構造体に&(アドレス演算子) または newキーワードを使って初期化するとポインタ型で受け取ることができます。

u4 := &User{Name: "taro", Age: 30} // var u4 *User

u5 := new(User) // var u5 *User
u5.Name = "taro"

ちなみにGoだと、構造体は下記のような初期化関数を作るのが一般的らしいです。

func newUser(name string, age int, email string) *User {
    u := new(User)
    u.Name = name
    u.Age = age
    u.email = email
    return u
}

var user *User = newUser("taro", 30, "hoge@example.ac.jp")

メソッド

Goの構造体にはもう1つ便利な機能があります。それがメソッドです。
下記構文でメソッドを定義することができます。

func (レシーバ名  レシーバの型) 関数名(引数) (戻り値) {
    //処理
}

では上記で作った、User構造体にメソッドを定義して使ってみましょう。

func (u User) greet() string {
    return "hello," + u.Name;
} 

var user *User = newUser("taro", 30, "hoge@example.ac.jp")
user.greet()

greetメソッドではレシーバーにUserを指定しています。メソッドはフィールドと同じように、「.」 を使ってアクセスします。
メソッドではレシーバ(User)のもつフィールドにアクセスすることが可能です。
また、同じ名前のメソッドがあっても、レシーバが異なればメソッドは別のものとして扱われるので注意してください。

以上。
もし何か間違っている等のご指摘があればご連絡ください。
長くなりましたが、最後まで読んで頂きありがとうございました。
次回は「Go言語を真剣に勉強してみた〜パッケージ編〜」です。

よろしければ、Go言語を真剣に勉強してみた〜環境構築編〜もご覧ください。

watataku8911
駆け出しのwebエンジニアです。
http://watataku.php.xdomain.jp
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