torutkのブログ

ソフトウェア・エンジニアのブログ

初めてのテレワーク

初めてテレワークを実施した

先週12/1に転職し、3日間通勤しました。転職先はテレワークを導入しています。そこで、土日で疎通確認を実施して良好だったので月曜日は在宅勤務でテレワークを実施しました。前職ではテレワーク適用はない部署であったので、人生初のテレワークでした。

先週の3日間は、新しい勤務先で慣れない環境であったこともあり、かなり緊張していたので疲労も著しいものがありました。とくに水分を十分とる余裕がなかったです。

週明けの月曜日は、テレワークで自宅のため、ちょっとした合間に水分を取ることもでき、静かで落ち着いて作業ができました。天候も曇りで暑すぎることもなく(冬は太陽の軌道が低く、晴れの日は窓から日光が部屋の中まで差し込み温室状態になります)、快適に過ごしました。

ただし、一日の歩数は著しく低下してしまいました。朝ちょっと買い物にでたときと、昼弁当を買いに出たときに歩いただけです。まだ仕事のペースがつかめず、途中で休憩やストレッチする余裕がまったくなく、体がガチガチになってしまいました。

あとは、テレワークではWeb会議で込み入った話をするときに、ホワイトボードに書きながらということができないので替わりのツールを見つけ使いこなさないといけないなと思いました。

あるいは小さなホワイトボードに手書きでカメラに写すとか?

MacBook を初めて使う

仕事で使うPCで、WindowsMacかの選択肢が与えられた

転職し、この12月1日から新しい会社での勤務が始まりました。 貸与されるPCは、WindowsMacから選択が可能でした。 今回、あえてMacを選択してみました。MacであればUNIXシェル環境が使え、いろいろなプログラミングがやりやすそうであるし、ここでmacOSを使ってみるもの楽しみと考えてのことです。

Macは昔PowerPC 601を搭載したPowerMacintosh 7500(OSが漢字Talk 7.5)を購入し使っていましたが、それ以降はWindowsマシンを中心に、ときどきLinuxマシンを使っていました。

貸与されたのは、13インチMacBook Pro です。

ちなみに職場で周囲をみるとほとんどがWindowsマシンで、MacBookは少数派のようでした。

WindowsユーザーがMacに移るときにはまる事柄(使い始め数日まで編)

WindowsユーザーがMacを触ると、やはり違いにはまります。ここでは使い始めて3日ほど、メール、ブラウザ、Microsoft Officeのドキュメント閲覧等で困ったことを中心にメモします。

テキストのコピー・ペーストができない

キーバインドが違うので、Windows流の Ctrl-C, Ctrl-Vではコピーペーストができません。また、右クリックでポップアップメニューをだそうとトラックパッドの右隅をクリック(Windowsユーザー目線では右クリック)してもだめでした。

しばらくして、ああコマンドキー(⌘)をつかうんじゃなかったかなと⌘-C ⌘-V でコピーペーストができるようになりました。

トラックパッドで右クリックができない

1) Ctrlキーを押しながら左クリック、または 2)トラックパッドを2本指でタッチすると右クリックになりました。

システム環境設定のトラックパッドで、右クリックの操作を変更することはできますが、ここはデフォルトのまま使って慣れるようにします。

もともとマウスはボタン1つというMacintoshのユーザーインタフェースの流れが残っているような操作感です。

スクロールバーがでないことがある

Webブラウザで作業しているときに、カーソルを右端付近に持って行ってもスクロールバーがでないことがわりと頻繁にあります。macOSでは、スクロールバーは必要に応じて表示されるようになっていますが、「必要に応じ」に反応してもらえないような状況です。 回避策としてはカーソルキーの上下キーでスクロールさせることはできますが、ブラウザ閲覧中はトラックパッドに指を置いているのでキーボードを使うのが煩雑となります。 そこで、設定でスクロールバーを常時表示としました。[システム環境設定] > [一般] で、スクロールバーの表示を[常に表示]に変更します。

  • 別な回避策)トラックパッド上を2本指で上下にスライドすることでスクロールできます
Microsoft Office文書やPDF閲覧時のページ送りができない

Windowsでは、PgUp、PgDn キーで、Office文書やPDF文書をページ単位で前後に閲覧することができました。 Macでは、そのようなキーが見当たりませんが、次の方法があるようです。

Windowsでの操作キー MacBookでの操作キー
PgUp fn + ↑
PgDn fn + ↓
Home fn + ←
End fn + →

トラックパッド上でのジェスチャでもページ送り機能があるようです。 * トラックパッド上を2本指で左右にスライドするとページ送りができるようです

表示の拡大縮小はどうやれば?

Office文書やブラウザの表示を拡大・縮小する方法が分かりませんでした。

トラックパッド上でのジェスチャでできるようです。

  • 2本指でピンチ操作
  • 2本指でダブルタップ ⇒ Officeツールでは反応なし、Webブラウザではスマートズーム(コンテンツに応じ拡大⇔縮小)
画面キャプチャはどうすれば?

スクリーンショットというアプリケーション(ツール)を使います。スクリーンショットの実行は次のどちらかで可能です。

スクリーンショットはデフォルトではデスクトップに自動でファイル名を付けて保存するので、クリップボードにコピーしたい場合は、スクリーンショットのオプションで設定を変更します。

Doc(画面下側のアプリケーション起動ショートカットツール)の設定を変えたい

デフォルトでは、業務では使わないツールが画面下側のDocに並んでいます。不要なアイコンをDocから削除するには、次の方法があります。

  • Docからアイコンを削除するには、アイコンをDocから上へ一定距離ドラッグしてドロップ
  • アイコンを右クリックしオプション > 削除

必要なツールをDocに登録したいときは次の方法があります。

  • Launchpadを開き、アプリケーションのアイコンをDocにドラッグ&ドロップ
Docのアイコンの大きさを変えたい

システム環境設定のDocとメニューバーから、Dockサイズの変更が可能です。

UNIXシェル環境

Launchpadから、その他 > ターミナル でUNIXシェル環境のターミナルが開きます。 デフォルトでは、zshとなっています。

トラックパッドのいろいろな操作

MacBookトラックパッドでは、いろいろなジェスチャー機能があるようです。

support.apple.com

T.B.D.

周辺機器を使うには

MacBook Pro 13インチ(2020年)本体にあるコネクタ類は、USB Type-C インタフェースが2つとサウンド端子(3.5mmΦ)が1つあるだけです。電源は USB Type-Cに接続します。外付けディスプレイへの出力はUSB Type-Cに繋ぎます。するとそれでUSBコネクタが埋まってしまうので、マウス、USBメモリ、有線LAN、USBヘッドセットなどを使うにはUSBハブを追加する必要があります。

MacBook用のUSBハブとして、HDMI、USB Type-A、有線LAN(RJ-45)、SD/microSD、給電USB Type-Cを具えたものが製品化されています。例のひとつを次に示します。

https://www.amazon.co.jp/dp/B075FW7H5J

OpenJDKディストリビューション情報

OpenJDKディストリビューション情報を取得する

OpenJDKコミュニティでオープンソース開発され、GPLv2クラスパス例外で提供されるOpenJDKソースをいくつかの組織がビルドしOpenJDKバイナリを提供しています。組織としては、Oracleを始め、Eclipseファウンデーション、Azul Systems、Red HatAmazonMicrosoft、BellSoft、SAPなどかなりの数に上っています。

これらの情報を、提供元サイトを巡って集めるのは結構大変な作業となります。

Disco API

JavaとOpenJDKに関するコミュニティ foojay.io から、OpenJDKの様々なディストリビューションを見つける汎用のAPI(Web API)が提供されています。

github.com

例えば、JDK 16でWindows OS用、Intelプロセッサ、JavaFX同梱、zip形式配布のOpenJDKディストリビューションに関する情報を入手するには、次のようにWeb APIにリクエストします。

D:\work> curl -o result.json "https://api.foojay.io/disco/v2.0/packages?
package_type=jdk&operating_system=windows&latest=available&
javafx_bundled=true&version=16&architecture=x64&archive_type=zip"
  • https://api.foojay.io/disco/v2.0/packages
    Disco APIのRESTエンドポイントの1つでJDK(JRE)パッケージの情報を取得する際に使用
  • package_type
    JDKを指定(他にJRE指定可)
  • operating_system
    windowsを指定(他にはmacos, linux, aixなど)
  • latest
    指定したJDKバージョンの最新マイナーバージョンを対象
  • javafx_bundled
    JavaFXを同梱しているJDKを指定
  • version
    JDKバージョン(メジャーバージョン)を指定
  • architecture
    CPU種類を指定
  • archive_type
    JDK配布パッケージの形式を指定

Disco API への呼び出し結果は次となりました。 ディストリビューションが2つ該当(zulu、liberica)、バージョンは 16.0.2です。

{
    "result":
    [{"id":"0d09e5c63678ab962efc9988b65c9f50",
      "archive_type":"zip",
      "distribution":"zulu",
      "major_version":16,
      "java_version":"16.0.2+7",
      "distribution_version":"16.32.15",
      "latest_build_available":true,
      "release_status":"ga",
      "term_of_support":"sts",
      "operating_system":"windows",
      "lib_c_type":"c_std_lib",
      "architecture":"x64",
      "package_type":"jdk",
      "javafx_bundled":true,
      "directly_downloadable":true,
      "filename":"zulu16.32.15-ca-fx-jdk16.0.2-win_x64.zip",
      "ephemeral_id":"a3b40394e66ee48a1937e844b2ad89b6030cd796",
      "links":{
      "pkg_info_uri":"https://api.foojay.io/disco/v2.0/ephemeral_ids/a3b40394e66ee48a1937e844b2ad89b6030cd796"
      },
      "free_use_in_production":true,
      "feature":[]
     },

     {"id":"e7ffd61f0b054a386784bb6cd322b473",
      "archive_type":"zip",
      "distribution":"liberica",
      "major_version":16,
      "java_version":"16.0.2+7",
      "distribution_version":"16+7",
      "latest_build_available":true,
      "release_status":"ga",
      "term_of_support":"sts",
      "operating_system":"windows",
      "lib_c_type":"c_std_lib",
      "architecture":"amd64",
      "package_type":"jdk",
      "javafx_bundled":true,
      "directly_downloadable":true,
      "filename":"bellsoft-jdk16.0.2+7-windows-amd64-full.zip",
      "ephemeral_id":"e2179bcc00206df48e94432454d7602c67d177ba",
      "links":{
      "pkg_info_uri":"https://api.foojay.io/disco/v2.0/ephemeral_ids/e2179bcc00206df48e94432454d7602c67d177ba"
      },
      "free_use_in_production":true,
      "feature":[]
     }],

    "message":"2 package(s) found"
}

Disco API を呼び出すクライアントツールがいくつか提供されています。

主要なIDEプラグイン、主要なブラウザのプラグインが提供されるほか、スタンドアロンツールも提供されています。

JDK Butler

Disco APIを呼び出すスタンドアロンのクライアントツールです。

github.com

WindowsmacOSLinux 用のインストーラが提供されます。また、同各OS用の実行可能JARファイルが提供されます。 JavaFXGUIを作成しているJavaアプリケーションです。

GUIJDKメジャーバージョン、マイナーバージョン、ディストリビューション名、OS、libc種類、CPU種類、アーカイブ種類と選択していくことでOpenJDKディストリビューションをダウンロードします。

画面操作例

JDKMon

PCにインストールされているOpenJDKディストリビューションを検出・一覧表示し、アップデートがあるかどうかを確認するツールです。

github.com

WindowsmacOSLinux 用のインストーラが提供されます。また、同各OS用の実行可能JARファイルが提供されます。 JavaFXGUIを作成しているJavaアプリケーションです。

Windowsでは、デフォルトでC:¥Program Files¥Java ディレクトリ下を検索、他のディレクトリにインストールしたJDKは手動で検索パスを設定することで検出されます。

Java読書会「マイクロサービスパターン」開始

Java読書会BOF 新しい課題図書「マイクロサービスパターン」を読む会を開始

本日8月29日より、Java読書会BOF主催の読書会「マイクロサービスパターン」を読む会が始まりました。

この本は、前回の課題図書投票で2位になっており、今回リベンジで課題図書となりました。

第1回

書籍のカバーのそでに記載される書籍紹介から読み始めました。電子書籍の人はカバーのそでがないという事態に。。。

第1章は、仮想のオンラインフードデリバリ会社FTGOの企業アプリケーションがモノリシック地獄の症状を示しているところから、マイクロサービスアーキテクチャへの切り替えに向かうための準備となります。

第1章の要旨

FTGOアプリケーションは、ヘキサゴナルアーキテクチャの下、外部のWebサービスを活用し論理的にモジュール化して作られ、1つのJava WARファイルにパッケージングしています。  ⇒ モノリシック

アプリケーションが小さい初期は、開発・変更・テスト・デプロイ・スケーリングしやすいと、さまざまな利点がありました。 成功を収め、次々新機能を実装するにつれコードが大きく複雑になり、コードベースと開発チームが大きくなるにつれ、複雑さに委縮、開発ペースの遅れ、デプロイに時間がかかる、スケーリングが難しい、信頼性が低い、陳腐化する技術スタック(フレームワークや言語)に縛られるといった、さまざまな問題が生じるようになりました。  ⇒ 泥だんご

そこでFTGOのCTOであるメアリーは、FTGOアプリケーションをマイクロサービスアーキテクチャに移行すると結論しました。

3軸のスケーリングの話、Y軸スケーリングではアプリケーションをサービスに分割、サービスを互いに疎結合API以外では通信できない、手段の一つが個々のサービスに専用のデータベースを持たせる、といったマイクロサービス版のFTGOの概要を紹介。

続いて、マイクロサービスとSOAの比較、マイクロサービスの利点、欠点、そしてパターン言語とマイクロサービスアーキテクチャにおける各パターンのリストアップ(詳細は後続の章で解説)です。

章の最後にプロセスと組織に触れ、チームオブチームスでオーバーヘッドを抑えて開発、テスト、デプロイを素早く行う(DevOps)、といった内容です。

ヘキサゴナルアーキテクチャ

ヘキサゴナルアーキテクチャは、第1章で突如登場し、第2章で多用されています。書籍には由来は記載なかったようですが、調べると、Alistair Cockburn博士が提唱したアーキテクチャパターンの1つで別名をPort and Adapterというものでした。Cockburn博士の記事の日本語訳が次に掲載されています。

blog.tai2.net

なぜ六角形なのか、は必要に応じてポートとアダプタを挿入するための余地としてとりあえず6としたようです。

アーキテクチャとして従来より多用されているレイヤーパターンの欠点を解消するものです。アダプターパターンや依存性反転(DI)パターンを組み合わせています。

第2章の要旨

ソフトウェアアーキテクチャの定義について、4+1ビューモデル、階層化スタイルとヘキサゴナルアーキテクチャスタイル、サービスとは何か、疎結合、共有ライブラリの疎結合への影響などについてざっと解説をした後、マイクロサービスアーキテクチャによるアプリケーションの作り方について述べています。

サービスの分割方法

2つのパターン

  • Decompose by business capability
  • Decompose by sub-domain

前者は、業務による分割で、まあ割とすんなり分かったような気になる分割です。後者はドメイン駆動設計(DDD)のサブドメインですが、この本だけでは分かりにくいです。

分割のガイドラインとして、ロバート・C・マーティン氏による次の原則を取り上げています。

  • 単一責任の原則(Single Responsibility Principle)
  • 閉鎖性共通の原則(Common Closure Principle)

第1回の感想

本書籍「マイクロサービスパターン」は、ソフトウェアの分析設計に関する本だった、というのが(今更ながら)読み始めてみて分かりました。

高水準ドメインモデルの作成では、アプリケーション要件(ユーザーストーリ・シナリオ)からモデルとしてのクラスと操作を抽出しますが、このあたりは「実践UML」に倣ったとあります。

サービスの抽出では、「ドメイン駆動開発(DDD)」を採用しています。

両方をある程度知っていることが望ましいので、できれば両方かじっておくとよいのですが、どちらの本も厚く難しい(特にDDD)ので躊躇してしまいます。

ということで、一人で読むのは厳しい書籍で読書会向きというところは間違いないです。

Electron開発環境をWindows上で用意する

Electron開発環境をWindows上に用意する

GUIアプリケーションをJavaで作った場合とElectronで作った場合の配布イメージサイズと展開後のサイズを比較するため、初めてのElectron開発環境を整えます。OSはWindowsです。

npmコマンドありきのインストール手順が氾濫

最初の躓きは、Electron開発環境を用意する手順の最初で、npmコマンドが前提となっていることでした。 これは公式サイトに記載されるインストール記事 Installation | Electron でもそうでした。

公式サイトのドキュメントトップページには、 「このドキュメントの読み手はNode.jsと一般的なWeb開発に親しんでることを前提にしている」 とのことで、どうやら開発環境を用意するのにもNode.jsがあって当然となっているようです。

npmとは

Node.jsと呼ぶJavaScript実行環境で使われるパッケージ管理ツール(npm:Node Package Manager)とのことです。

Electronは、Node.jsとChromiumを組み込んだJavaScript、HTMLそしてCSSで記述するデスクトップアプリケーション基盤です。

インストールすべきもの

Node.js

まず、Node.jsをインストールします。バージョンは、Electronの公式サイトにその時点の安定板、ベータ版、アルファ版、ナイトリービルド版における組み合わせを参照します。

f:id:torutk:20210809215900p:plain
Electron Release

本日(2021-08-09)時点のバージョン番号は次です。

構成名 バージョン
Electron 13.1.7
Node 14.16.0
Chromium 91.0.4472.124

そこで、Node.js の 14.16.0をインストールしてみることにします。 次のページから、Node.js 14.16.0 のダウンロードを辿り、Windows用のインストーラを入手します。

nodejs.org

インストーラは、node-v14.16.0-x64.msi と node-v14.16.0-win-x64.zip があります。ここではMSI形式を入手しました。環境変数PATHを設定してくれるので楽ですが、複数バージョンのNode.jsを使い分けるときはMSI形式でない方がよいかもしれません。

Electron

次のコマンドでElectronをインストールします。 コマンドを実行したディレクトリにElectronのファイル群がダウンロードされます。

D:\work\electron_hello> npm install electron --save-dev

> core-js@3.16.1 postinstall D:\work\electron_hello\node_modules\core-js
> node -e "try{require('./postinstall')}catch(e){}"

Thank you for using core-js ( https://github.com/zloirock/core-js ) for polyfilling JavaScript standard library!

The project needs your help! Please consider supporting of core-js:
> https://opencollective.com/core-js
> https://patreon.com/zloirock
> https://paypal.me/zloirock
> bitcoin: bc1qlea7544qtsmj2rayg0lthvza9fau63ux0fstcz

Also, the author of core-js ( https://github.com/zloirock ) is looking for a good job -)


> electron@13.1.8 postinstall D:\work\electron_hello\node_modules\electron
> node install.js

npm WARN saveError ENOENT: no such file or directory, open 'D:\work\electron_hello\package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open 'D:\work\electron_hello\package.json'
npm WARN hello No description
npm WARN hello No repository field.
npm WARN hello No README data
npm WARN hello No license field.

+ electron@13.1.8
added 87 packages from 97 contributors and audited 87 packages in 82.565s

6 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

ダウンロードされるファイル群は200MB弱になります。

Helloアプリケーション作成

www.electronjs.org

Electronのインストールと順番は逆かもしれませんが、package.jsonファイルを作成します。

npm init コマンドで対話的に作成するか、エディタで記述します。 以下はnpm initコマンドで対話的に作成した例です。

{
  "name": "hello-app",
  "version": "1.0.0",
  "description": "Hello, World!",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "TAKAHASHI,Toru",
  "license": "MIT"
}

startでelectronを起動するよう修正します。

  "scripts": {
    "start": "electron ."
  },

main.js を作成します。

const { app, BrowserWindow } = require('electron')

function createWindow() {
    const win = new BrowserWindow({
        width: 320,
        height: 200
    })

    win.loadFile('index.html')
}

app.whenReady().then(() => {
    createWindow()
})
  • 注)app.on でactivate時、window-all-closed時の処理は省略
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Hello, Electron World!</title>
    </head>
    <body>
        <p>Hello, Electron World!</p>
    </body>
</html>

実行します。

D:\work\electron_hello> npm start
> hello-app@1.0.0 start D:\work\electron_hello
> electron .

f:id:torutk:20210809233816p:plain

配布

パッケージ作成ツールをインストールします。

D:\work\electron_hello> npm install --save-dev @electron-forge/cli
  :
D:\work\electron_hello> npx electron-forge import
  :

パッケージを作成します。

D:\work\electron_hello> npm run make

> hello-app@1.0.0 make C:\Users\toru\Documents\electron\learn\hello-app
> electron-forge make

✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: squirrel
✔ Making for target: squirrel - On platform: win32 - For arch: x64

outディレクトリの中に配布パッケージが生成されます。

out\
  +-- make\squirrel.windows\x64\
        +-- hello-app-1.0.0 Setup.exe
        +-- hello_app-1.0.0-full.nupkg

配布パッケージのファイルサイズは80MB強でした。

hello-app-1.0.0 Setup.exe を実行すると、C:\Users\<ユーザー名>\AppData\Local\hello-app\ の下にインストールされました。 コントロールパネルのプログラム一覧にも記載されています。

開発・配布・展開サイズ

このhello-appプログラムの開発ディレクトリ、インストーラファイル、インストール後に展開されたディレクトリのそれぞれの容量を次に示します。

種類 容量(MB) 備考
開発ディレクト 680MB ビルド後のサイズ(配布イメージファイル含む)
配布ファイル(インストーラ 78MB Windowsの場合
展開ディレクト 256MB

最後に

  • Node.js使えて当然、のドキュメントは、厳しい
  • プログラム開発(npmコマンド実行時)、インターネット接続が必要でまた 時間がかかる

Electronは、Webアプリケーション開発者が持つ HTML、CSSJavaScript のノウハウをそのまま使ってデスクトップアプリケーションをまるでWebアプリケーション開発であるかのように作る開発・実行環境という印象です。非Webアプリケーション開発者がElectronに取り組むには、Webアプリケーション開発スキルの基礎がないと大変です。

また、Webアプリケーション分野のツールなので、インターネット接続がマストです。

Rust事始め(続)

Rustのソースファイル構成

Rust では、標準のビルド&パッケージ管理システム Cargo を使いビルドを行います。 このビルドでは、ソースファイルのディレクトリ及びファイル名にかなり独特の制約があります。

単一のソースファイルから単一の実行ファイルを作成する Cargoパッケージ

お馴染みの Hello worldプログラムの構成です。

任意の作業ディレクトリにて、次のcargoコマンドでバイナリクレートを1つ持つパッケージを作成します。

D:\work> cargo new hello_world
  • パッケージとは、クレートをビルド・テスト・共有する単位(ひとまとまりのビルド)です。
  • クレートとは、実行可能ファイルまたはライブラリファイルを生成する単位です。前者をバイナリクレート、後者をライブラリクレートと呼びます。
  • cargo newコマンドでパッケージを作成します。パッケージ名をコマンドの引数で指定します(ここでは hello_world )。デフォルトではバイナリクレートを1つ持つパッケージが生成されます。

生成されるディレクトリツリーは次となります。

hello_world
  +-- src
  |    +-- main.rs
  +-- Cargo.toml

srcディレクトリ直下に生成されるソースファイル main.rs は、バイナリクレートのクレートルートとなり、このファイルからビルドを開始し、このファイルから辿れるモジュールが芋づる的にビルドされます。 このバイナリクレートの名前は、パッケージ名と同じ(ここではhello_world)です。

次のcargoコマンドでクレートをビルドします。

D:\work\hello_world> cargo build
   Compiling hello_cargo v0.1.0 (D:\work\hello_world)
    Finished dev [unoptimized + debuginfo] target(s) in 1.16s

複数のソースファイルから単一の実行ファイルを作成する Cargoパッケージ

モジュール機能を使い、複数のソースファイルから構成されるプログラムをビルドします。 ソースファイルを分割する場合は、モジュールに切り出してモジュールの階層に基づくディレクトリおよびファイル名を持つソースファイルとする必要があります。

クレートルートからモジュール参照

クレートルート(ここではmain.rs)から、別ファイルに定義されるモジュールを利用します。 クレートルートから直接参照するファイルは、クレートルートが置かれているディレクトリ(src)に、モジュール名に基づくファイル名(ここではgreeting.rs)で配置します。次のディレクトリツリーに示します。

hello_world
  +-- src
  |    +-- main.rs
  |    +-- greeting.rs
  +-- Cargo.toml

main.rsに、モジュールgreetingを参照する記述を入れます。これにより、モジュール名に基づく名前のソースファイル(greeting.rs)をビルドに含めます。

mod greeting;
fn main() {
    println!("{}", greeting::greet());
}

greeting.rsに記述する要素は、mod greeting {...} と定義しなくても、モジュールgreetingに含まれたものとして扱われます。

pub fn greet() -> String {
    String::from("Hello, world!")
}
モジュールの階層化

上述のgreetingモジュールから、さらに別ソースファイルに記述された別モジュール(ここではgreeting::time_class)を参照します。 クレートルートからのモジュール階層に基づき、greeting::time_classモジュールを定義するソースファイルはgreeting/time_class.rs となります。

hello_world
  +-- src
  |    +-- main.rs
  |    +-- greeting.rs
  |    +-- greeting
  |          +-- time_class.rs
  +-- Cargo.toml

greetingモジュールのソースファイル中に time_class モジュールへの参照を記述します。

mod time_class;
pub fn greet() -> String {
    format!("Hello, world!, {}", time_class::classify(12))
}

time_classモジュールのソースファイルはモジュール名に基づき time_class.rs とし、パッケージ階層に基づき src/greeting/time_class.rs に配置します。

pub fn classify(hour: u32) -> &'static str {
    match hour {
        0 ..=4 => "midnight",
        5 ..=8 => "morning",
        9 ..=16 => "daytime",
        17 ..=19 => "evening",
        20 ..=23 => "night",
        _ => "out of range"
    }
}
さらにモジュール階層を深くする

モジュール greeting::time_class::morning を定義する場合、morningモジュールのソースファイルは次の様に配置します。

hello_world
  +-- src
  |    +-- main.rs
  |    +-- greeting.rs
  |    +-- greeting
  |          +-- time_class.rs
  |          +-- time_class
  |                +-- morning.rs
  +-- Cargo.toml
mod.rs というファイル(Rust 2015の場合)

Rust 2015 では、モジュールディレクトリに mod.rs という特定のファイル名を配置し、これがモジュールのソースファイルとして扱われます。 Rust 2018 でもこの振る舞いは継続して利用可能ですが、互換性のための利用に留めた方がよいと思います。

1つのパッケージに含めるクレートの制約

パッケージの制約として、1つのパッケージに含めることができるクレートは次となります。

  • 1個以上のクレートを持つ
  • ライブラリクレートは、0個または1個(2個以上は含められない)
  • バイナリクレートは、0個以上(複数個を含められる)

ワークスペースで複数パッケージを構成

プログラムの規模が大きくなると、複数のライブラリから構成したくなります。このときは、ワークスペースを用いて複数のパッケージを束ねます。

ワークスペース構成

まず、ワークスペースディレクトリを用意し、ワークスペースを定義するCargo.tomlファイルを配置します。

D:\work> mkdir hello_workspace
D:\work> cd hello_workspace
D:\work\hello_workspace> 

ワークスペースを作成するcargoコマンドはないようなので、手作業でディレクトリを作成します。

[workspace]

members = [
    "hello",
]

Cargo.tomlには、ワークスペースの定義を記述します。ワークスペースを構成するパッケージをmembersに記述します。まずは実行可能ファイルを生成するパッケージ hello を記述しました。後でライブラリを生成するパッケージを追記していきます。

helloパッケージをcargo newコマンドで生成します。

D:\work\hello_workspace> cargo new hello
     Created binary (application) `hello` package

D:\work\hello_workspace>

この時点でのディレクトリ構成は次となります。

D:\work\hello_workspace
    +-- Cargo.toml
    +-- hello
          +-- Cargo.toml
                +-- src
                      + main.rs
ワークスペースのビルド

ワークスペース直下のディレクトリで、cargo buildコマンドを実行します。

D:\work\hello_workspace> cargo build
   Compiling hello v0.1.0 (C:\Users\toru\study\rustw\learn\hello_workspace\hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.96s

D:\work\hello_workspace> 

ビルド成果物は、ワークスペース直下の target ディレクトリに生成されます。

D:\work\hello_workspace
    +-- Cargo.lock
    +-- Cargo.toml
    +-- hello
    |     +-- Cargo.toml
    |           +-- src
    |                 + main.rs
    +-- target
          +-- debug
ワークスペースにライブラリを生成するパッケージを追加

ワークスペースを定義するCargo.tomlにパッケージ名を記載しないで作成すると、次の様に警告メッセージが表示されます。

D:\work\hello_workspace> cargo new morning --lib
warning: compiling this new package may not work due to invalid workspace configuration

current package believes it's in a workspace when it's not:
current:   C:\Users\toru\study\rustw\learn\hello_workspace\morning\Cargo.toml
workspace: C:\Users\toru\study\rustw\learn\hello_workspace\Cargo.toml

this may be fixable by adding `morning` to the `workspace.members` array of the manifest located at: C:\Users\toru\study\rustw\learn\hello_workspace\Cargo.toml
Alternatively, to keep it out of the workspace, add the package to the `workspace.exclude` array, or add an empty `[workspace]` table to the package's manifest.
     Created library `morning` package

ワークスペースのCargo.tomlにmorningパッケージを追記します。

[workspace]

members = [
    "hello",
    "morning",
]

この時点のディレクトリ構成は次となります。

D:\work\hello_workspace
    +-- Cargo.lock
    +-- Cargo.toml
    +-- hello
    |     +-- Cargo.toml
    |           +-- src
    |                 + main.rs
    +-- morning
    |     +-- Cargo.toml
    |           +-- src
    |                 + lib.rs
    +-- target

ただし、この時点では hello クレートが morning クレートに依存していることが記載されていないのでビルドが通りません。

ワークスペース内のパッケージ間の依存性の記述

helloパッケージのCargo.tomlに依存性を記述します。

   :(前略)
[dependencies]
morning = { path = "../morning" }

Rust事始め

プログラミング言語 Rust を始めてみる

以前にRust言語が話題になっているのを目にして、どんな言語かと軽く情報収集をしました。

Rust 概要

C言語C++言語のようにシステムプログラミングに使える、性能、メモリ安全と並行性のサポートを重視し、手続き型、オブジェクト指向型、関数型のマルチパラダイムを提供する強い型付け言語がRustの特徴です。

コンパイル結果はOSネイティブの実行可能バイナリとして生成され、ガベージ・コレクタを使わず所有権によりメモリ安全性を確保、スレッド間のメッセージ授受やアトミックなアクセスなどによる安全な並行性の確保などが盛り込まれています。

Rust 言語についての日本語ドキュメント類が次のサイトにまとめられています。

Home | Rustの日本語ドキュメント/Japanese Docs for Rust

ただし、最新の情報はやはり英語のドキュメントを参照することが望ましいようです。

当面の事始めとして、次の日本語ドキュメントを見ながら進めていきます。

プログラミング言語Rust日本語版」

Rust の歴史、経緯

2010年に発表され、2015年にバージョン1.0がリリースされました。 2021年には非営利団体 Rustファウンデーションが設立され、Rustの資産は当初の開発元のMozillaから移管されることになります。Rustファウンデーションの設立メンバーは、AWS、ファーウェイ、GoogleマイクロソフトMozilla です。

Rustの開発環境(Windows

Windows上で Rust 開発環境を用意するには、Visual Studio または Microsoft C++ Build Tools が必要になります。Microsoft C++ Build Tools の利用は Visual Studioのライセンスが必要なので、いずれにせよ Visual Studio が必要となります。

Visual Studio のライセンスは基本有償です。無償のCommunityエディションを利用するには条件を満たす必要があります。

Visual Studio がインストールされているPCでのRust開発環境

次のサイトから、Windows 64bit用のインストーラ(rustup-init.exe)をダウンロードし実行します。 Install Rust - Rust Programming Language

実行すると、インターネットから必要なコンポーネントをダウンロードしつつインストールが実行されます。 デフォルトでは、インストールしたユーザーの %USERPROFILE%.cargo\bin にコマンド類が格納され、ユーザーの環境変数PATHに登録されます。

コマンドプロンプトを立ち上げ、rustc コマンドを実行するとコンパイルが実行できます。

Hello world

作業ディレクトリを作成(例、D:\work\hello)、Rustのソースファイル hello.rs を記述します。

fn main() {
    println!("Hello, world!");
}
  • 関数定義は、fn で開始し、関数名、引数、戻り値を記述。ここでは、関数名がmainで、引数なし、戻り値なしの関数を定義
    • 関数名mainはプログラムのエントリポイントを示す特別な関数
  • 関数本体は、波括弧で囲む。Rustのスタイルは、関数宣言と同じ行に空白1つあけて開き波括弧を置く
  • 関数内に、テキストをコンソールに表示するprintlnマクロを呼び出すコード println! を記述。インデントは空白4つ
  • 文字列はダブルクォートで囲む。セミコロンで行を終端(マクロ呼び出し式を終える)

rustc コマンドを実行しコンパイルをします。

D:\work\hello> rustc hello.rs
D:\work\hello> dir /w
[.]         [..]        hello.exe   hello.pdb   hello.rs
D:\work\hello> 

hello.exeが生成されています。また、デバッグ用シンボルファイル hello.pdb も生成されています。

hello.exe を実行します。

D:\work\hello> hello
Hello, world!

D:\work\hello> 
Visual Studio CodeでRust開発

Windows 環境でRust開発をするには、現在のところ Visual Studio Codeを使うのがよさそうです。 次のページを参照し、Visual Studio CodeでRust機能を設定します。 Windows で Rust 用の開発環境を設定する | Microsoft Docs

Visual Studio CodeでRust開発する際は、Rust標準ビルドシステム Cargo でプロジェクトを作成します。

その他

Emacs でRust開発をするには、rusticを入れるのがよさそうですが、設定方法が package機能を使うものしか見つけられず、素の設定が見出せなかったのでいったん保留(挫折ともいう)。

Rustは、標準でビルドツール(Cargo)が備わっているので、OS毎に異なるビルド環境を用意しなくて済むようです。

Rustのオブジェクト指向型のサポートは、C++を始めとするクラスベースとはちょっと異なります。structおよびenumでデータを定義し、implでstructのメソッドを定義します。ポリモーフィズムはtraitで定義します。馴染むのに少々かかりそうです。

変数はデフォルトで不変です。

ドキュメントコメントが提供され、ソースコードのコメントからドキュメントを生成します。

C言語との相互運用性はありますが、C++言語とは直接の相互運用性はなく、C++側でC言語ラッパー(extern "C")を用意する必要があります。

標準ライブラリは貧弱、外部ライブラリを利用することが多くなりそう。

Wikiに随時記載中

Rustについてかじったことを随時Wikiに記載しています。 www.torutk.com