LoginSignup
0

posted at

updated at

【A Tour of Go】メソッド編

公式の 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
}

次回

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
What you can do with signing up
0