質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.33%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

1回答

176閲覧

Golangにてポインタがどうしても理解できません、、

sato32

総合スコア0

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

0クリップ

投稿2025/02/01 08:44

udemyにてGoの勉強しているのですがさっぱり理解できなく困っております。(雑すぎてすみません)出来るだけ詳しく順を追って解説してくださるかたいらっしゃいましたら助けてください。
package main

import "fmt"

// Vertex構造体の定義
type Vertex struct {
x, y int
}

// 値レシーバのAreaメソッド
func (v Vertex) Area() int {
return v.x * v.y
}

// ポインタレシーバのScaleメソッド
func (v *Vertex) Scale(i int) {
v.x = v.x * i
v.y = v.y * i
}

// New関数Vertexのポインタを返す
func New(x, y int) *Vertex {
return &Vertex{x, y}
}

func main() {
v := New(3, 4) //Vertexインスタンスを作成
v.Scale(10)
fmt.Println(v.Area())
}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TWSNMP

2025/02/01 10:58

// ポインタレシーバのScaleメソッド func (v *Vertex) Scale(i int) { v.x = v.x * i v.y = v.y * i } を // 値レシーバのScaleメソッド func (v Vertex) Scale(i int) { v.x = v.x * i v.y = v.y * i } にした時と結果を比べてみると何かわかるかもしれませんよ。
guest

回答1

0

ポインタとは整数値をアドレスとして扱う型です
アドレスはポインタにキャストされた整数値です
ではこのアドレスで何を指すかといえば、それはメモリ内におけるデータの格納場所です

単純な例から考えます

func main() { var x int var y *int y=&x *y=2 fmt.Println(x) }

var式は変数宣言です
ここではint型の変数及びポインタを生成しています
ポインタyは変数xのアドレスを取得しています
一度アドレスを保持すると、以降はyからxの領域へアクセスできるようになります
アクセス時の宣言が*yです
アクセスした領域に対しては代入も可能です
この操作は参照外しと呼ばれます

これを踏まえて、例のコードを確認します

package main import "fmt" // Vertex構造体の定義 type Vertex struct { x, y int } // 値レシーバのAreaメソッド func (v Vertex) Area() int { return v.x * v.y } // ポインタレシーバのScaleメソッド func (v *Vertex) Scale(i int) { v.x = v.x * i v.y = v.y * i } // New関数Vertexのポインタを返す func New(x, y int) *Vertex { return &Vertex{x, y} } func main() { v := New(3, 4) //Vertexインスタンスを作成 v.Scale(10) fmt.Println(v.Area()) }

レシーバとはメンバを呼び出すインスタンスのことです
ここではVertex構造体のインスタンスがそれに当たります
*Vertexはこのインスタンスのポインタです

New関数が戻り値にそのポインタを返しています
冒頭でも触れたように、ポインタの正体はアドレスとして振る舞う整数なので、通常の整数と同じく戻り値として扱えます

ここでは&Vertex{x,y}としてインスタンス化直後のVertexのアドレスを直接返しています
関数を抜けるので一見このインスタンスは消滅しそうに思われますが、Goの仕様によってアドレスを返すインスタンスは動的にヒープへ確保されるため、その心配はありません

例えば以下のコードは有効です

func main() { var x *int=test() fmt.Println(*x) } func test () *int{ x:=100 return &x }
100

AreaScaleの二つの関数はレシーバとして指定されるデータ型がそれぞれ異なっています

// 値レシーバのAreaメソッド func (v Vertex) Area() int { return v.x * v.y } // ポインタレシーバのScaleメソッド func (v *Vertex) Scale(i int) { v.x = v.x * i v.y = v.y * i }

ここでAreaVertex型のインスタンスのコピーを受け取る関数であり、ScaleVertex型のインスタンスのポインタに対応する関数です

データ型の違いは、関数のそれぞれの役割を表しています
インスタンスのコピーを渡すということは、コピーされたインスタンスに対する変更が元のインスタンスには反映されないことを意味します
逆にポインタを渡す場合はインスタンスの格納場所を参照させることになるため、インスタンスの値を直接書き換えられる状態であることを示します

つまりポインタを値渡しすれば、インスタンスはコピーされません
Scaleはポインタを通じてインスタンス内の値を書き換える関数であると分かります
対するAreaはコピーを受け取るのでこれがインスタンスの値を変更する目的の関数でないと読み取れます
この関数の役目はインスタンス内のメンバの値を掛け合わせた結果を返すことです

ここまでの内容を振り返り、改めてmainの手続きに注目します

func main() { v := New(3, 4) //Vertexインスタンスを作成 v.Scale(10) fmt.Println(v.Area()) }

Newでポインタを獲得し、Scaleで変更し、Areaで結果を返すという、一連の目的に沿ったプログラムになっていることが分かります

なお、コピーが渡せるならば、Newの実際の戻り値はポインタでなくとも構わないのではないかと思うかもしれません
これは実際にその通りです
しかし、その場合インスタンスのコピーによる計算負荷を考慮する必要があります
ポインタであれば生成したばかりのインスタンスをそのまま使い回せます

とはいえヒープで扱うよりスタックでインスタンスを管理する方が速度的には優位です
計算に必要な空間量を鑑みて適切な使い分けを心掛けましょう

投稿2025/02/01 14:28

Manabu

総合スコア93

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.33%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問