以前に書いた記事 GO言語でクラスっぽいことをする の中で触れられなかった「カプセル化をGo言語で実現する方法」について書いていこうと思います。
ポリモフィズムに関しては今回も省略します。(いつか書きたい)
やりたいこと
- コンストラクタでPrivate変数の初期値を設定する
- Publicメソッドを外部から参照して実行する
- Publicメソッド内でPrivate変数を利用する
- Publicの定数を参照して利用する
- Private変数の値を参照しようとするとエラーになることを確認する
全網羅じゃないけどよく使いそうな処理
実装例
package main
import (
"fmt"
"xxx.example.com/sample/human"
)
const line = "--------------------"
func main() {
wiz := new(human.Human)
wiz.Init("魔法少女", 10, 10)
fmt.Println(human.Msg)
fmt.Println(line)
fmt.Println(wiz.Hello())
fmt.Println(wiz.Attack())
fmt.Println(line)
human.Hoge()
// wiz.hp undefined (cannot refer to unexported field or method hp)
// wiz.hp = 100
// wiz.name undefined (cannot refer to unexported field or method name)
// fmt.Println(wiz.name)
}
package human
import "fmt"
const (
// Msg ...
Msg = "人類を作成してください..."
)
// Human ...
type Human struct {
name string
hp int
ap int
}
// Init ...
func (h *Human) Init(name string, hp, ap int) {
h.name = name
h.hp = hp
h.ap = ap
}
// Hello ...
func (h *Human) Hello() string {
return fmt.Sprintf("こんにちは、私は%sです。", h.name)
}
// Attack ...
func (h *Human) Attack() string {
return fmt.Sprintf("%sの攻撃!%dのダメージ!", h.name, h.ap)
}
package human
import "fmt"
// Hoge ...
func Hoge() {
war := new(Human)
war.Init("+‡†狂戦士†‡+", 10, 15)
fmt.Println(war.Hello())
fmt.Println(war.Attack())
fmt.Println(war.name + "はフォルムチェンジした!")
war.name = "俺TSUEEEEEEEE"
war.ap = 100000
fmt.Println(war.Attack())
}
実行結果
人類を作成してください...
--------------------
こんにちは、私は魔法少女です。
魔法少女の攻撃!10のダメージ!
--------------------
こんにちは、私は+‡†狂戦士†‡+です。
+‡†狂戦士†‡+の攻撃!15のダメージ!
+‡†狂戦士†‡+はフォルムチェンジした!
俺TSUEEEEEEEEの攻撃!100000のダメージ!
+‡†狂戦士†‡+はチーターであることが判明しました
実装内容の説明
前記事 GO言語でクラスっぽいことをする と被ってそうなところは省略します
外部からアクセス可能な要素
Go言語では「先頭が大文字の要素」は外部パッケージからもアクセスできます。
今回の例では const Msg
type Human struct
func Hello()
などがそれに当たります。(他にもあります)
ここでは出てきませんが変数も指定可能です。
外部からアクセス不能な要素
Go言語では「先頭が小文字の要素」は外部パッケージからアクセスできません。
今回の例では Human.name
などがそれに当たります。(他にもあります)
ここでは出てきませんが定数やメソッド、関数も指定可能です。
外部からアクセス不能な要素を指定した場合
// wiz.hp undefined (cannot refer to unexported field or method hp)
wiz.hp = 100
// wiz.name undefined (cannot refer to unexported field or method name)
fmt.Println(wiz.name)
そんな要素は存在しないものとしてコンパイルエラーになります。
同パッケージのファイルからは先頭小文字でもアクセス可能
war.name = "俺TSUEEEEEEEE"
war.ap = 100000
先頭小文字の要素であっても、同パッケージ内であれば好きに参照することができます。
+‡†狂戦士†‡+に好き勝手動かれたくない場合は別パッケージから使用するのがよいでしょう。
まとめ:Go言語でカプセル化するには
- パッケージを分ける
- 外部から参照されたくない要素は「先頭小文字」で定義する