Go 言語でパッケージを自作して、それを呼び出してみる – その1

はじめに

前回は、外部モジュールの呼び出し方を学びました。

世界中の優秀なエンジニアの方々が作成したモジュールを利用できれば、できることの幅が随分広がります。

そんな便利な部品 モジュール を自作してみようというのが今回のエントリです。

検証環境

$ head -n 2 /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"

$ go version
go version go1.16.2 linux/amd64

モジュール作成の前に用語整理をしておきます

モジュールの作成の前に。
用語が増えだしたので、頭の中を整理しておきたいと思います。

ここからは Go 言語のいくつかの基本的な特徴を紹介していきます。

学習のゴール

今回の学習のゴールは、2 つのモジュールを作成するところまでとします。

  1. 1 つ目は他のライブラリまたはアプリケーションからインポートされることを目的とした ライブラリの作成
  2. 2 つ目は先に作成したライブラリを利用する アプリケーションの作成

チュートリアルを読む限りだと、ライブラリとアプリケーションいづれも モジュール と呼ぶようです。

  • モジュール = ライブラリ or アプリケーション

学習の流れ

モジュール作成まで、 7 つの工程をすすめます。
それぞれの工程で、できるかぎり Go 言語の特徴に触れていきます。

  1. モジュールの作成
    • モジュールをコーティングします。モジュールの中に関数を配置します。
  2. 作成したモジュールを他のモジュールから呼び出す
    • 作ったモジュール野中の関数を、他のモジュールから呼び出してみます。
  3. エラーの返却
    • 単純なエラーを発生させ、それを呼び出し元でハンドリングしてみます。
  4. ランダムに挨拶文を返却させてみる
    • slice(Go 言語の動的なサイズの配列)としてデータを返却し操作します
  5. 複数の人々に挨拶文を返却する
    • map を使って key-value の値を作成します
  6. テストコードを追加
    • 作成したコードをテストするために、ビルドインのユニットテスト機能を使ってみます
  7. アプリケーションをコンパイルし、インストールする
    • ローカル PC 内で自分のコードをコンパイルし、インストールしてみます

前提条件・推奨条件

Go 言語 のチュートリアルを進めるにあたって、以下の前提条件を満たしておくことをお勧めされていました。

  1. Go 言語 以外のプログラミング経験
    • チュートリアルで記述することは非常にシンプルですが、いくつかの関数は C 言語や Java など他のプログラミング言語でも同様の機能を持っているものが登場します。
    • 他のプログラミング言語経験したことがあれば理解が容易になります
  2. 使い慣れたテキストエディタ
    • 多くの適正化が Go 言語 をサポートしています。例えば VSCode 、 GoLand それから Vim。
  3. 使い慣れたターミナル.
    • 使い慣れたターミナルがあればそちらを使いましょう。
    • Linux macOS であれば標準の Terminal を使うことも出来ます。 Windows であれば PowerShell や cmd を利用できます。

モジュール作成開始!

それではいよいよ Go 言語のモジュールを作成してみます。
他の開発者も利用できるようなモジュールを作ってみましょう、

ちなみに、モジュールの中には機能や特徴が関係している関数をグループ化して入れておきます。
全く関係のないものを寄せ集めてモジュール化するのは、他の人が理解しにくくなるのでやめておいた方がいいでしょう。

それから モジュールパッケージGo 言語のソースコードの三つの関係を改めて整理しておきます。

  • Go 言語のソースコード : 言わずもがなソースコードです。
  • パッケージ : Go 言語のソースコードをグループ化したもの
  • モジュール : パッケージをグループ化したもの

ようやく少し用語が整理できてきました。

自分が作成するモジュールには、そのモジュールが利用する以下の情報を記述しておく必要があります。

  • Go のバージョン
  • 他モジュールのリスト

モジュールに新しい機能を追加したり、直したりした場合は、 新しいバージョンのモジュール として公開します。
僕たちの作ったモジュールが、意図せず最新のものに変わってしまった場合、利用者は当惑するはずです。
明示的にバージョンアップをすることで、このような混乱を避けることができます。
モジュールのバージョンが上がったとしても、利用者が自分でバージョンアップを行わない限りは自動的にバージョンが上がることは有りません。

コーディング開始!

それではコーディングを進めていきます。
以下の手順を進めていけば大丈夫です。

1. ターミナルと開きます

2. ターミナルに以下のように入力します

ホームディレクトリに移動しましょう。

$ cd

Windows OS の場合には以下のコマンドを入力します。

% cd %HOMEPATH%

3. ソースコード配置ディレクトリを作成し、移動します

# greetingsディレクトリを作成
mkdir greetings

# 作成したディレクトリに移動
cd greetings

4. モジュールの作成を開始します。

go mod init コマンドを実行します。

こちらも前回のブログエントリで実行したコマンドになります。

アプリケーションを作る場合またはライブラリを作る場合のどちらの場合でも、 go mod init は必要ということですね。

前回実行した時と同様に、 モジュールの名前 を引数として渡します。
文字の名前は前回同様 github のリポジトリ名をイメージして命名 しましょう。

僕の場合だと genzouw/greeting というリポジトリ名にあるのが良いかと思います。

$ go mod init genzouw/greetings
go: creating new go.mod: module genzouw/greetings

コマンドを実行すれば go.mod というファイルがディレクトリに作成されるはずです。
この時点で go.mod ファイルには、以下の 2 つの情報だけが書かれているです。

  • モジュールの名前
  • モジュールがサポートする go のバージョン
$ cat go.mod
module genzouw/greetings

go 1.16

5. テキストエディタを開いて greetings.go というファイルを作成します。

ex: vi greetings.go

6. greetings. go に以下のコードを貼り付けて保存します

package greetings

import "fmt"

// Hello returns a greeting for the named person.
func Hello(name string) string {
    // Return a greeting that embeds the name in a message.
    message := fmt.Sprintf("Hi, %v. Welcome!", name)
    return message
}

これが今回作成するモジュールの一番最初のコードです。
この関数は呼び出し元に挨拶文を返します。

次のステップではこの関数を呼び出すアプリケーションをコーディングします。

コードを簡単に解説してみます。
このソースコードでは、以下のようなことを行っています。

  • グループ化して格納するための greetings という名前のパッケージを宣言
  • 挨拶文を返却する Hello という名前の関数を実装
    • この関数は name という名前のパラメーターを 1 つ受け取ります。
    • name パラメーターは string 型です。
    • またこの関数は string 型の値を 1 つ返却します。

さらに関数の名前に特徴があります。
Go 言語では先頭の 1 文字目が大文字で始まる関数は、同じパッケージ以外からも呼び出すことができます。
逆に言うと先頭を小文字で始まる関数は同じパッケージ内からしか呼び出すことができません。

この仕組みは Go 言語の中では exported name という名前で呼ばれています。

  • message という名前の変数を宣言し挨拶文を格納しています。
    • Go 言語では := 演算子は、 変数の宣言と初期化を行うためのシンタックスシュガー となっています。
    • 変数を宣言と同時にできるだけ初期化したほうがにくいので頻繁に利用する演算子だと思います。
    • この演算子を使わない場合は、以下のようにあえて冗長に書くこともできます。
var message string
message = fmt.Sprintf("Hi, %v. Welcome!", name)
  • 挨拶文を生成するために fmt パッケージの Sprintf 関数を利用しています。
    • 関数の第 1 引数は string 型でフォーマットを指定しています。
    • %v の部分は変数に置き換えられます。
    • 最後にこの関数は生成された挨拶文を、呼び出し元に返却します。

本日はここまでです。

ひとこと

実行できなかったため、本当に正しくコーディングできたのか不明のままで気持ち悪さが残ります。

次のステップでは、 作成した関数を別のモジュールから呼び出してみたい と思います。

Posted by genzouw