Go言語についての3つくらいの誤解

以下、自分の思い込みもあるとは思うが、あまり気にしないで書いてみる。

Goは短く書くための言語ではない

短く書けるようにした結果、落とし穴が発生したり、 読みにくくなったり誤解が生じる余地があるならば、 そのような書き方は排除されている。

貴方が書きたいコードは、誰にでも読みやすいコードなのか、 誤解の余地がまったくないコードなのか、そのあたりをよく考えてほしい。

サポートされていない機能は未来永劫サポートしないとは限らない

例外は将来的にもサポートされないだろうが、 ジェネリクスは優先度が低いとされているだけで、 別に未来永劫サポートしないわけではない。

ただ、複雑性が増すなど課題が多いのと、 ジェネリクスがなくても済ませられるケースが多いため、 後回しにされているだけである。

Goはあらゆる問題を解決する言語ではないし、誰にでも使ってもらおう等と譲歩した言語でもない

RubyJava のように、あらゆる課題を解決しようなどと思い上がった言語ではない。 不得意分野は不得意分野と割り切っている。

また、誰にでも使ってもらうなどと考えている言語でもない。 気に入らないのなら、選択肢は他に幾らでもあるだろう。

以上、ソースはないよ。コメントもらっても回答しないかも

PowerShell で書く、Go言語プログラムのリリース管理的なアレ(3)バージョン文字列の設定

バッチファイルの話もするとたいへんなので、以下 PowerShell だけという方向で:

Go ソースへの埋め込み

これは簡単で、

go build "-o" nyagos.exe -ldflags "$ldflags -X main.version=$version"

だけでよい。これで main パッケージの version という変数に $version の内容が設定される。 Go ソース側で受け皿となる変数の宣言を忘れないように。

var version string

Windows プロパティーへの埋め込み

ちょっとめんどう。goversioninfo というツールを使う。 (make.cmd では Make-SysO という関数内で行っている)

    .\goversioninfo.exe `
        "-file-version=$version" `
        "-product-version=$version" `
        "-icon=mains\nyagos.ico" `
        ("-ver-major=" + $v[0]) `
        ("-ver-minor=" + $v[1]) `
        ("-ver-patch=" + $v[2]) `
        ("-ver-build=" + $v[3]) `
        ("-product-ver-major=" + $v[0]) `
        ("-product-ver-minor=" + $v[1]) `
        ("-product-ver-patch=" + $v[2]) `
        ("-product-ver-build=" + $v[3]) `
        "-o" nyagos.syso `
        versioninfo.json

(PowerShell で逆クォートは、UNIX系のバックスラッシュみたいな役割を担っている)

基本の情報は versioninfo.json に記しておいて、変更がよく発生するところだけ、オプションで変更する。 このコマンドで生成されたnyagos.sysoというファイルを go build するフォルダーにおいておくだけで、 これらの情報が実行ファイルに埋め込まれる。

Windows にはバージョン番号のプロパティーが複数ある。

  • 製品バージョン(product-version)
  • ファイルバージョン(file-version)

NYAGOS では両者は同じ扱いにしているが、大きなパッケージソフトウェアでは、パッケージ全体のバージョンを product-version とし、個別ファイルのバージョンはファイルバージョンとするのが普通のようだ。

さて、これらのバージョンには「バージョン文字列」と4つの数値:「メジャーバージョン」「マイナーバージョン」「ビルドナンバー」「パッチナンバー」をそれぞれに持っている。

Windowsエクスプローラで EXE ファイルのプロパティー→詳細タブを開くと、バージョン情報が表示されるが

  • 製品バージョンは、バージョン文字列(-product-version=)がそのまま表示される
  • ファイルバージョンは、「メジャーバージョン(-ver-major=)」「マイナーバージョン(-ver-minor=)」「パッチナンバー(-ver-patch=)」「ビルドナンバー(-ver-build=)」をピリオドで連結したテキストが表示される。

ようになっているようだ。

なお、古い goversioninfo.exe には「-product-ver-*****」という引数はない (わしがプルリク送った)。

最新版をゲットしてくれ…といいたいところだが、make.cmd には最新版の goversioninfo.exe を自動で入手してくれる機能がある(続く)

PowerShell で書く、Go言語プログラムのリリース管理的なアレ(2)バージョン文字列の取得

方針としては

  • リリースビルドの時は、テキストファイル(Misc\version.txt)に記載のテキスト
  • スナップショットの時は、git describe --tags の結果

を使うことにしている。これはバッチファイルでも比較的簡単だ。 リリースビルドなら

for /F %%I in (%~dp0Misc\version.txt) do set "VERSION=%%I"

だし、スナップショットなら

for /F %%I in ('git describe --tags') do set "X_VERSION=-X main.version=%%I"

だ(若干変数が違うがスルーしていただきたい)。

これが PowerShell だと、もっと簡単で、リリースビルド:

Build  (Get-Content Misc\version.txt)  ""

となる。Build はビルドするための関数で第一引数のバージョン文字列を取る形になっている。スナップショットは

 Build (git describe --tags) ""

だけで済む。PowerShell では括弧が逆クォート的な役割を担っている(文法的には式を展開する的な意味)。

うん、つまらないところなので、早くも飽きてきた(おい)。 次はもう少し面白いはずの、バージョンを設定するところを書こう。

PowerShell で書く、Go言語プログラムのリリース管理的なアレ(1)目次

NYAGOS は 4.2.1 まではバッチファイルで、以下の作業を行っていた。

  • 実行ファイルの作成
    • バージョン文字列の取得
      • リリース(make release)の時はテキストファイル(Misc\version.txt)
      • スナップショット(引数なし make)の時は git describe --tags を使用
    • バージョン文字列・アイコンの埋め込み
      • Go言語のソースへのバージョン文字列埋め込み
      • Windows のプロパティとしてのバージョン文字列・アイコンの埋め込み
    • nyagos.d 以下のファイルの EXE ファイル内への埋め込み(実は nyagos.d が存在しない場合にデフォルトとして利用するようになっている)
    • 必要最小限の go fmtDOSファイルシステムアーカイブビットを利用している)
    • 作成CPUアーキテクチャの判断
      • goarch.txt があれば、その中身を %GOARCH% に設定する
      • goarch.txt がなければ、go version の結果から %GOARCH% を設定(不要だが、後の処理を合わせるため)
    • 必要に応じて go generate の実行
  • リリース用 ZIP ファイル作成(make package)
  • C言語定数の Go ソース化(make constgcc)
  • make clean
  • make get(サブディレクトリ全部に対する go get
  • 実行ファイルのバージョン・アーキテクチャの確認(make status

NYAGOS 4.2.2 では、これらをだいたい PowerShell に置き換えた。

気が向いたら、順次説明してゆきたい

n番煎じの powershell 向け shebang !

PowerShellスクリプトを実行しようとすると、実行ポリシーを一時的に変えるため

powershell -ExecutionPolicy RemoteSigned -file HOGE.ps1

と長い起動コマンドラインになってしまいがちです。

ということで、HOGE.ps1 を実行するために、別途 HOGE.cmd などのバッチファイルを用意したりしますが、ファイルが増えると、配布する手間、説明する手間(「二つを同じフォルダーに置いて実行してください!」とか)も増え、しかも使ってもらえなくなったりして、なかなか難儀です。

そこでバッチファイルの中に PowerShell スクリプトを組み込んで、1ファイル化しようということになります。過去、PowerShell をバッチファイルに組み込む方法は、過去いろいろ記事がありました。

そんな中、先日見つけた記事:

これはかなり決定打のように思われました。echo がバッチコマンド、PowerShell 両方にある(echo = Write-Outputエイリアス)ことを利用するなど、よく考えられたものです。ただ、惜しまれるのはバッチとの共用行が長くて、覚えづらいということでしょうか。

そこで、自分なりにアレンジしてみました。

@set "args=%*"
@powershell "iex((@('')*3+(cat '%~f0'|select -skip 3))-join[char]10)"
@exit /b %ERRORLEVEL%

Write-Output $env:args

# vim:set ft=ps1:
  • プログラム的にバッチファイルの先頭3行を空行に差し替えて、Invoke-Expression(iex)で処理するようにした(3行を差し替えずに、そのまま消してもよかったのだが、エラーの行番号がズレさせたくなかったため)
  • 改行を表す「\"`n\"」を [char]10 などに置き換えた(エディターのシンタックスハイライトに優しい)
  • 引数は残念ながら $args[] ではなく、$env:args を使う(とほほ)

しかし、こういうのも、多分、どこかで既出なんでしょうね

海底神殿から金塊を受領しました

今から海底神殿から金塊を受領しまーす(だいたい水抜き済み、全エルダーガーディアン討伐済み) f:id:zetamatta:20171001133439p:plain

f:id:zetamatta:20171001133552p:plain f:id:zetamatta:20171001133733p:plain

底に穴をあけると金ブロックが!

f:id:zetamatta:20171001133847p:plain

金ブロック8個(金のインゴット72個相当)いただきました!

海底神殿を攻略すると、スポンジ、ランタンが入るのが大きくて、金ブロックはおまけみたいなもんですが、それでもおいしいですよね。ご馳走様でした

.oO(しかし水抜きが大変なんだよな。途中までエルダーガーディアンの呪いがうざいし)

その後

f:id:zetamatta:20171001134523p:plain

全てのシーランタンは略奪され、かぼちゃランタンにすりかえられていた。誰がこんなひどいことを!(犯人はシルクタッチのつるはしを持っているな…)

GoのEnum表現は、go:generate + stringer の出番?

主旨が違うかもしれないんだけど、そういうのは go:generate + stringer の出番と違うかなと思った。

package main

import "fmt"

type SkuNameEnum int

//go:generate stringer -type=SkuNameEnum

const (
    Free SkuNameEnum = iota
    PerNode
    Premium
    Standalone
    Standard
    Unlimited
)

func main(){
    for i := Free ; i <= Unlimited ; i++ {
        fmt.Println( i )
    }
}
$ go generate
$ go build
$ ls
foo.go                skuname.exe*          skunameenum_string.go
$ skuname.exe
Free
PerNode
Premium
Standalone
Standard
Unlimited
$