TL; DR
- Goの構文をよりスクリプト言語っぽく手軽に
- Goの標準パッケージが利用可能
- シェルとして使用可能
はじめに
GitHubのプログラミング言語タグを見ていたところ、Go+
という言語を見つけました。
READMEによると「エンジニアリング」「理工系の教育」「データサイエンス」向けを謳っているようです。
名前の通りGo言語互換で、さらに +
となるいくつかの機能が追加されていました(JavaScriptに対するTypeScript的なイメージ)。
本記事では、Go+で面白いと思った構文について紹介したいと思います。
バージョン
- Go+:
v1.1.8
(執筆時点の最新)
実行方法
まずは公式のガイドに従い gop
をインストールします。Homebrewで入れると楽でした。
コマンドの使い方は go
コマンドと同様です (gop run
, gop build
等)。
gop run
した場合、gopファイルをgoファイルにトランスパイルしてから実行されます。中間生成物のgoファイルは gop_autogen.go
で確認できます。
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
package main
import fmt "fmt"
func main() {
//line main.gop:4
fmt.Println("Hello, world!")
}
構文の違い
基本はGoと互換性がありますが、記述量を抑えるためのいくつかの構文が拡張されています。
関数呼び出しのかっこが不要
fmt.Println("Hello, world!")
を
fmt.Println "Hello, world!"
と書けます。後述のDSLを書く際に少し見栄えが良くなります。
(ちなみに、print系は組み込みでも定義されているので、fmtをimportせずに println
でも呼び出せます)
コレクション
配列やマップのリテラルに型を書く必要がありません。
// 型は勝手に推論される
words := ["foo", "bar", "baz"] // []string
vals := ["Hi", 10] // []any
// mapも同様
{"Hello": 1, "xsw": 3}
for文
range
の代わりに <-
を使用します。
import "fmt"
func main() {
words := ["foo", "bar", "baz"]
for word <- words {
fmt.Println(word)
}
for i <- 1:5 {
fmt.Println(i)
}
}
内包表記
内包表記も使えます。
fmt.Println([w[0:1] for w <- words]) // ["f", "b", "b"]
?によるエラーハンドリング
?
を使うことで、エラーハンドリングを暗黙的に行うことができます。
func add(x, y string) (int, error) {
return strconv.Atoi(x)? + strconv.Atoi(y)?, nil
}
このコードは以下と同様です。
func add(x, y string) (int, error) {
xi, err := strconv.Atoi(x)
if err != nil {
return 0, err
}
yi, err := strconv.Atoi(y)
if err != nil {
return 0, err
}
return xi + yi, nil
}
これ、Rustで一番好きな構文なので「Goで使えたらいいな」といつも妄想してました、
もう if err != nil
まみれとは言わせない
lambda
Goの関数リテラルよりもシンプルに書けます。
// ジェネリクスは未対応っぽい
func Map(nums []int, f func(int) int) []int {
return [f(n) for n <- nums]
}
func main() {
fmt.Println(Map([1,2,3], n => n * 2))
// 普通のGoっぽくも書ける
fmt.Println(Map([1,2,3], func(n int) int {return n * 2}))
}
演算子のオーバーロード
自作の型で演算子を定義できます。
import "fmt"
type MyInt int
func (i MyInt) +(other MyInt) MyInt {
// そのまま i + other とすると無限ループするので注意!
return MyInt((int(i) + int(other)) % 10)
}
func main() {
a := MyInt(9)
b := MyInt(3)
fmt.Println(a + b) // 2
}
その他
Go+では、DSLのように特定の用途向けのフレームワークを作る機能(ClassFile
)があります。
この機能を使って、Goの文法でシェルのようにコマンド実行ができるライブラリもあるようです。
...が、残念ながら最新版では互換性の問題で動作しませんでした。バージョンを下げても動かないのでやむなく断念...
おわりに
以上、Go+言語の紹介でした。
Goらしさは残しつつ、痒い所に手が届く文法が足されているのが嬉しいです。小さなツールをサクッと作るのに向いていそうです。
関連記事