0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Go言語(Golang)におけるポインタレシーバと値レシーバ

Last updated at Posted at 2024-10-14
package main //liststart1

import (
	"fmt"
	"time"
)

type Counter struct { // Counter型を定義
	total             int  // 合計
	lastUpdated time.Time  // 最終更新時刻
}

func (c *Counter) Increment() { // ポインタレシーバ(cはポインタ)
	c.total++
	c.lastUpdated = time.Now()
}

func (c Counter) String() string { // 値レシーバ(cにはコピーが渡される)
	return fmt.Sprintf("合計: %d, 更新: %v", c.total, c.lastUpdated)
} 


func main() { 
	var c Counter
	fmt.Println(c.String())
	c.Increment()  //「(&c).Increment()」と書かなくてもよい
	fmt.Println(c.String()) 
} 

Counter型の定義

type Counter struct {
	total       int          // 合計
	lastUpdated time.Time    // 最終更新時刻
}

ここでは Counter という構造体を定義しています。この構造体は total(合計値)と lastUpdated(最終更新時刻)という2つのフィールドを持っています。

Increment メソッド

func (c *Counter) Increment() {
	c.total++
	c.lastUpdated = time.Now()
}

このメソッドはポインタレシーバを使用しています。ポインタレシーバとは、メソッドがポインタ型のレシーバを受け取ることを意味します。この場合、c*Counter 型のポインタです。

  • 理由: ポインタレシーバを使うと、メソッド内で構造体のフィールドを直接変更できます。これは、構造体が大きい場合や、メソッド内で状態を変更する必要がある場合に特に重要です。

String メソッド

func (c Counter) String() string {
	return fmt.Sprintf("合計: %d, 更新: %v", c.total, c.lastUpdated)
}

こちらは値レシーバを使っています。値レシーバは、メソッドが構造体のコピーを受け取ることを意味します。

  • 理由: 値レシーバを使うと、元の構造体を変更することなく、その値を取得することができます。この場合、Counter の状態を変更する必要がないため、値レシーバを使用しています。

main 関数

func main() {
	var c Counter
	fmt.Println(c.String()) // 初期状態を表示
	c.Increment()           // カウンタをインクリメント
	fmt.Println(c.String()) // 更新後の状態を表示
}
  • var c CounterCounter 型の変数 c を初期化します。この時点では total は 0、lastUpdated はゼロ値(1900年1月1日)です。
  • c.String() で初期状態を表示します。この時、値レシーバの String メソッドが呼ばれ、カウンタの合計と最終更新時刻が表示されます。
  • c.Increment() を呼び出すと、ポインタレシーバの Increment メソッドが実行され、total が 1 増加し、lastUpdated が現在の時刻に更新されます。
  • 再度 c.String() を呼び出して、更新された状態が表示されます。

Go言語では、メソッドを呼び出す際に、レシーバの型によって自動的にポインタが解決されるため、&c と書かなくても大丈夫です。この仕組みを詳しく説明します。

レシーバの自動解決

Increment メソッドはポインタレシーバ (*Counter) を使用しています。
c.Increment() と書くと、Goは cCounter 型の値であることを認識し、自動的にポインタを取って &c を実行します。
そのため、c.Increment() は実際には (&c).Increment() と同じ意味になります。

まとめ

  • ポインタレシーバ: 構造体のフィールドを変更する必要がある場合に使用します。メモリ効率が良い。
  • 値レシーバ: 構造体の状態を変更する必要がない場合に使用します。元のオブジェクトを安全に保つことができます。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?