エクスポートと非エクスポート
CoddyのGOジャーニー「論理とフロー」セクションの一部。レッスン 52/68。
Go では、識別子(変数、関数、型など)の可視性は、単純な命名規則によって制御されます。これによって、他のパッケージのコードがあなたの識別子にアクセスできるかどうかが決まります。
エクスポートされた識別子は大文字で始まり、他のパッケージからアクセスできます。「public(公開)」と考えてください。あなたのパッケージをインポートする人なら誰でも使用できます。
// これらはエクスポートされます(公開されます)
var Name string
func Calculate() int
type Person struct非公開識別子は小文字で始まり、同じパッケージ内でのみアクセスできます。これらはパッケージ内で「非公開」です。
// これらはエクスポートされていません(非公開です)
var age int
func helper() string
type config structこの命名規則は、public や private のようなキーワードを使わずにアクセスを制御する Go の方法です。別のパッケージからエクスポートされていない識別子を使おうとすると、その識別子はパッケージの外から見えないため、Go はコンパイルエラーを出します。
チャレンジ
簡単エクスポートされた識別子とエクスポートされていない識別子の命名規則を正しくすることで、Go パッケージの可視性に関する問題を修正します。他のパッケージからアクセスしたときにコンパイルエラーが発生する、誤った名前の識別子が含まれる、複数のパッケージを模したシナリオに取り組みます。
入力は2つです。
- パッケージ定義を含む文字列。形式は
"package_name:identifier1:type1:visibility1,identifier2:type2:visibility2|package_name:identifier1:type1:visibility1"(例:"utils:helper:function:private,Calculate:function:public|main:name:variable:private,Version:variable:public")です。 - アクセスの試行を含む文字列。形式は
"accessing_package.identifier1,accessing_package.identifier2,accessing_package.identifier3"(例:"main.helper,main.Calculate,utils.Version")です。
課題:
- 最初の入力をパイプで分割し、個々のパッケージ定義を取得する
- 各パッケージ定義をコロンで分割し、パッケージ名と識別子を取得する
- 各識別子の定義をコロンで分割し、識別子名、型、意図された可視性を取得する
- 識別子名と意図された可視性を受け取り、修正後の名前を返す
fixIdentifierNameという関数を作成する:- 可視性が
"public"の場合、識別子の先頭が大文字になるようにする - 可視性が
"private"の場合、識別子の先頭が小文字になるようにする
- 可視性が
- パッケージ分析のヘッダーを表示する:
"=== PACKAGE VISIBILITY ANALYSIS ===" - 各パッケージについて、パッケージ情報を表示する:
"Package: [package_name]"- パッケージ内の各識別子について:
- 識別子名の修正が必要な場合:
"- [original_name] ([type]) -> [corrected_name] (visibility: [visibility])" - 識別子名が正しい場合:
"- [identifier_name] ([type]) (visibility: [visibility]) ✓"
- 識別子名の修正が必要な場合:
- 2つ目の入力をカンマで分割し、個々のアクセスの試行を取得する
- 各アクセスの試行をドットで分割し、アクセス元のパッケージとアクセス対象の識別子を取得する
- アクセス検証のヘッダーを表示する:
"=== ACCESS VALIDATION ===" - 各アクセスの試行について、アクセスが有効かどうかを判定する:
- 識別子を含むパッケージを見つける
- 修正後の識別子名の先頭が大文字かどうかを確認する(エクスポート済み)
- 識別子がエクスポートされている場合:
"[accessing_package] accessing [target_package].[corrected_identifier_name]: ✓ ALLOWED (exported)" - 識別子がエクスポートされていない場合:
"[accessing_package] accessing [target_package].[corrected_identifier_name]: ✗ DENIED (unexported)" - 識別子が存在しない場合:
"[accessing_package] accessing unknown.[identifier_name]: ✗ NOT FOUND"(パッケージ名としてunknownを出力する。この試行は拒否されたアクセスとして数える)
- 集計情報を数えて表示する:
"=== SUMMARY ===""Total packages analyzed: [number_of_packages]""Total identifiers processed: [total_number_of_identifiers]""Identifiers requiring fixes: [number_of_identifiers_that_needed_fixing]""Access attempts: [number_of_access_attempts]""Allowed accesses: [number_of_allowed_accesses]""Denied accesses: [number_of_denied_accesses]"
- 最後に推奨事項を表示する:
- 修正が必要な識別子があった場合:
"Recommendation: Fix identifier naming to follow Go conventions" - すべての識別子が正しかった場合:
"All identifiers follow proper Go naming conventions"
- 修正が必要な識別子があった場合:
入力文字列の分割には strings パッケージ、書式付き出力には fmt パッケージを使用し、文字列操作関数で識別子名を確認・変更してください。この課題では、Go の命名規則がパッケージの可視性を制御する仕組みを示し、エクスポートされた識別子とエクスポートされていない識別子の違いを理解できます。
自分で試してみよう
package main
import (
"fmt"
"strings"
)
func main() {
// 入力を読み取る
var packageDefinitions string
var accessAttempts string
fmt.Scanln(&packageDefinitions)
fmt.Scanln(&accessAttempts)
// TODO: 以下にコードを書く
// fixIdentifierName関数を作成する
// パッケージ定義を解析する
// パッケージの分析結果を表示する
// アクセス試行を解析する
// アクセスの検証結果を表示する
// 集計統計を計算して表示する
// 推奨事項を表示する
}このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
論理とフローのすべてのレッスン
自分で練習してみよう: Goオンラインコンパイラ