構造体のメソッド
値レシーバーとポインターレシーバーの違い
「構造体のメソッド」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
メソッドとは
メソッドは、レシーバ引数を持つ関数です。レシーバはfuncキーワードとメソッド名の間に記述され、関数を型に結び付けます。
値レシーバ
値レシーバは構造体のコピーを受け取ります。状態を変更する必要がないメソッドで使用します。
package main
import "fmt"
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 {
return 3.14159 * c.Radius * c.Radius
}
func main() {
c := Circle{Radius: 5}
fmt.Printf("%.2f\n", c.Area()) // 78.54
}ポインタレシーバ
ポインタレシーバを使用すると、メソッドで構造体を変更できます。大きな構造体ではより効率的です。
package main
import "fmt"
type Counter struct{ N int }
func (c *Counter) Increment() { c.N++ }
func (c *Counter) Reset() { c.N = 0 }
func main() {
c := Counter{}
c.Increment(); c.Increment()
fmt.Println(c.N) // 2
c.Reset()
fmt.Println(c.N) // 0
}ポインタレシーバを使う場合
次の場合はポインタレシーバを使用します。
- メソッドでレシーバを変更する必要がある場合
- 構造体が大きい場合(コピーを避けられます)
- 一貫性を保つ場合。いずれかのメソッドがポインタレシーバなら、すべてのメソッドをそうするべきです
構造体が小さく、メソッドがデータの読み取りだけを行う場合は、値レシーバを使用します。
メソッド式とメソッド値
メソッドは第一級値として使用できます。
package main
import "fmt"
type Adder struct{ Base int }
func (a Adder) Add(n int) int { return a.Base + n }
func main() {
a := Adder{Base: 10}
fn := a.Add // method value — bound to a
fmt.Println(fn(5)) // 15
}構造体以外の型のメソッド
構造体に限らず、同じパッケージ内の任意の名前付き型にメソッドを定義できます。
package main
import "fmt"
type Celsius float64
func (c Celsius) ToFahrenheit() float64 {
return float64(c)*9/5 + 32
}
func main() {
t := Celsius(100)
fmt.Println(t.ToFahrenheit()) // 212
}ポインタの自動間接参照
メソッドを呼び出すとき、Goは自動的にアドレスの取得や間接参照を行います。手動で(&c).Method()と記述する必要はありません。
package main
import "fmt"
type Box struct{ Val int }
func (b *Box) Double() { b.Val *= 2 }
func main() {
b := Box{Val: 5}
b.Double() // Go auto-takes address
fmt.Println(b.Val) // 10
}メソッドチェーン
レシーバポインタを返すと、メソッドチェーン(ビルダーパターン)を使用できます。
package main
import "fmt"
type Builder struct{ result string }
func (b *Builder) Add(s string) *Builder {
b.result += s
return b
}
func (b *Builder) Build() string { return b.result }
func main() {
s := (&Builder{}).Add("Hello").Add(", ").Add("World").Build()
fmt.Println(s)
}Stringメソッド(fmt.Stringer)
String() stringメソッドを実装して、型の出力形式を制御します。
package main
import "fmt"
type Point struct{ X, Y int }
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.X, p.Y)
}
func main() {
p := Point{3, 4}
fmt.Println(p) // (3, 4)
}nilポインタのレシーバ
ポインタレシーバを持つメソッドは、nilポインタに対して呼び出すこともできます。デフォルトの動作を実装する場合に便利です。
package main
import "fmt"
type Node struct{ Val int }
func (n *Node) Value() int {
if n == nil { return 0 }
return n.Val
}
func main() {
var n *Node
fmt.Println(n.Value()) // 0
}一貫性の原則
Goの標準ライブラリと慣用的なGoコードでは、ある型のすべてのメソッドで同じ種類のレシーバを使用します。つまり、すべてポインタレシーバにするか、すべて値レシーバにします。混在させると、インターフェースで見つけにくいバグの原因になります。
簡単な確認
メソッドで構造体のフィールドを変更できるのは、どのレシーバ型ですか。
まとめ: メソッド
要点:
- メソッドでは
funcとメソッド名の間にレシーバを記述します - 値レシーバ: 読み取り専用、小さな構造体向け
- ポインタレシーバ: 変更、大きな構造体、一貫性の維持に適しています
- Goは自動的に間接参照するため、
(&v).Method()と記述する必要はありません - カスタム出力には
String() stringを実装します
練習問題
Balance float64フィールドを持つBankAccount構造体を定義してください。DepositとWithdrawのポインタレシーバメソッド、およびString()の値レシーバメソッドを追加してください。
よくある質問
「構造体のメソッド」レッスンは無料ですか?
はい。「構造体のメソッド」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「構造体のメソッド」で何を学びますか?
値レシーバーとポインターレシーバーの違い ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「構造体のメソッド」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。