LoginSignup
0
0

More than 1 year has passed since last update.

【A Tour of Go】メソッド編

Last updated at Posted at 2022-06-06

公式の A Tour of Go ではじめて Go 言語を触ってみました。

前回の記事(基本編)はこちら

以下、メソッドについて学んだことのメモ。

メソッド

基本

  • Go にはクラスの仕組みはないが、型にメソッドを定義できる
  • メソッドは、レシーバを引数にとる
    • レシーバはメソッドを定義する対象となる型
      • 構造体だけでなく任意の型にメソッドを定義できる
        • type MyFloat float64
    • レシーバを伴うメソッドを宣言するには、レシーバの型が同じパッケージ内に存在しなければならない
package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

// Vertex 型のメソッドを定義
// レシーバ: v Vertex
func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	v := Vertex{3, 4}
	fmt.Println(v.Abs()) // メソッドを使用
}
  • 同様の処理を、通常の関数として記述することも可能
func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
	v := Vertex{3, 4}
	fmt.Println(Abs(v))
}

ポインタレシーバ

  • ポインタレシーバを持つメソッドは、レシーバが指す変数を更新できる
  • レシーバ自身を更新する機会が多いため、変数レシーバよりもポインタレシーバのほうが一般的
    • 変数レシーバを持つメソッド: 変数のコピーを操作(関数の引数と同じ)
    • ポインタレシーバを持つメソッド: 変数そのものを操作
  • ポインタレシーバを用いることにより、メソッドの呼び出し毎に発生してしまう変数のコピーを避けることができる
    • レシーバが大きな構造体である場合に有効
package main

import (
	"fmt"
	"math"
)

type Vertex struct {
	X, Y float64
}

// 変数レシーバを持つメソッド
func (v Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

// ポインタレシーバを持つメソッド
func (v *Vertex) Scale(f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	v.Scale(10) // ポインタレシーバを持つメソッドの実行 => 変数 v 自身に対する操作
				// Go では利便性のために v.Scale(10) を (&v).Scale(10) として解釈する
	fmt.Println(v.Abs()) // 変数レシーバを持つメソッドの実行 => 変数 v のコピーに対する操作
}
  • ポインタレシーバを持つメソッドも、関数として書き換えられる
func Abs(v Vertex) float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func Scale(v *Vertex, f float64) {
	v.X = v.X * f
	v.Y = v.Y * f
}

func main() {
	v := Vertex{3, 4}
	Scale(&v, 10) // &v: 変数 v へのポインタ
	fmt.Println(Abs(v)) // 50
}

次回

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