LoginSignup
6
1

More than 3 years have passed since last update.

GO言語でカプセル化

Last updated at Posted at 2020-12-07

以前に書いた記事 GO言語でクラスっぽいことをする の中で触れられなかった「カプセル化をGo言語で実現する方法」について書いていこうと思います。
ポリモフィズムに関しては今回も省略します。(いつか書きたい)

やりたいこと

  • コンストラクタでPrivate変数の初期値を設定する
  • Publicメソッドを外部から参照して実行する
  • Publicメソッド内でPrivate変数を利用する
  • Publicの定数を参照して利用する
  • Private変数の値を参照しようとするとエラーになることを確認する

全網羅じゃないけどよく使いそうな処理

実装例

main.go
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)
}
human/human.go
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)
}
human.hoge.go
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言語でカプセル化するには

  • パッケージを分ける
  • 外部から参照されたくない要素は「先頭小文字」で定義する
6
1
1

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
6
1