公開フィールドと非公開フィールド
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 47/107。
Goでは、structレベルのカプセル化はfield名の大文字・小文字によって制御されます。この単純なルールによって、structが定義されているパッケージの外部からfieldにアクセスできるかどうかが決まります。
uppercase letterで始まるfieldsはexportedです:どのパッケージからもaccessibleです。lowercase letterで始まるfieldsはunexportedです:同じパッケージ内でのみaccessibleです:
// パッケージ "user" 内
type User struct {
Name string // エクスポート済み - どこからでもアクセス可能
Email string // エクスポート済み - どこからでもアクセス可能
password string // 未エクスポート - "user" パッケージ内でのみアクセス可能
age int // 未エクスポート - "user" パッケージ内でのみアクセス可能
}
別のパッケージがこの構造体をインポートして使用する場合、アクセスできるのは Exported fields のみです:
// パッケージ "main" 内
import "user"
func main() {
u := user.User{
Name: "Alice", // 動作する
Email: "a@mail.com", // 動作する
// password: "secret", // コンパイルエラー: 未知のフィールド
}
fmt.Println(u.Name) // 動作する
// fmt.Println(u.password) // コンパイルエラー: エクスポートされていないフィールドを参照できない
}
この仕組みは、機密データと内部実装の詳細を保護します。password フィールドはパッケージの外部から直接読み取ったり変更したりできないため、他のコードはあなたが提供するメソッドを使用する必要があります。これは、データ隠蔽を実現するための Go のアプローチです。データ隠蔽は、オブジェクト指向プログラミングにおけるカプセル化の基本原則です。
チャレンジ
簡単エクスポートされたフィールドとエクスポートされていないフィールドを通じたカプセル化を示す銀行口座システムを構築しましょう。機密性の高い金融データを保護しながら、安全な公開情報を提供するパッケージを作成します。
コードを2つのファイルに整理します。
account.go:mainパッケージに、適切なデータ保護機能を備えた実際の銀行口座をモデル化するBankAccount構造体を作成します。HolderName(エクスポート済み)- 公開表示しても安全な口座名義人の名前AccountType(エクスポート済み)- 口座の種類(例:"Savings"、"Checking")balance(エクスポートされていない)- 保護すべき実際の残高pin(エクスポートされていない)- 口座のPINであり、非常に機密性の高いデータ
NewBankAccountコンストラクター function を追加します。この function は名義人の名前、口座の種類、初期残高、PINを受け取り、新しいBankAccountへのポインターを返します。また、形式Account: [HolderName] ([AccountType])を返すGetPublicInfo() stringメソッドも追加します。main.go:入力から口座の詳細を読み取り、コンストラクターを使用してBankAccountを作成し、カプセル化を示します。メソッドを使用して公開情報を出力し、その後、エクスポートされた各フィールドに直接アクセスして、それぞれ別の行に出力します。エクスポートされていないフィールド(balanceとpin)は保護されています。これらを設定できるのはコンストラクターを通じてのみです。
次の入力が提供されます。
- 1行目:口座名義人の名前
- 2行目:口座の種類
- 3行目:初期残高(floatとして)
- 4行目:PINコード
たとえば、Alice Johnson、Savings、5000.50、1234が与えられた場合、出力は次のようになります。
Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: Savings残高とPINが出力に一度も表示されないことに注目してください。これらは構造体内に安全に隠され、パッケージ内でのみアクセス可能です。これがカプセル化の実例です。機密データを保護しながら、公開情報にはアクセスできる状態を維持します。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// 口座名義人の名前を読み取る
holderName, _ := reader.ReadString('\n')
holderName = strings.TrimSpace(holderName)
// 口座タイプを読み取る
accountType, _ := reader.ReadString('\n')
accountType = strings.TrimSpace(accountType)
// 初期残高を読み取る
balanceStr, _ := reader.ReadString('\n')
balanceStr = strings.TrimSpace(balanceStr)
balance, _ := strconv.ParseFloat(balanceStr, 64)
// PINを読み取る
pinStr, _ := reader.ReadString('\n')
pin := strings.TrimSpace(pinStr)
// TODO: コンストラクタを使用して新しいBankAccountを作成する
// account := NewBankAccount(...)
// TODO: GetPublicInfo()メソッドを使用して公開情報を出力する
// TODO: エクスポートされたフィールドに直接アクセスして名義人名を出力する
// fmt.Println("Holder:", ...)
// TODO: エクスポートされたフィールドに直接アクセスして口座タイプを出力する
// fmt.Println("Type:", ...)
// Note: balance と pin は unexported です - ここでは直接アクセスできません
// それらは構造体の中で安全にカプセル化されています
_ = balance // balance を使用するときにこの行を削除してください
_ = pin // pin を使用するときにこの行を削除してください
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ