20200216のGoに関する記事は7件です。

Go言語製のCUIツールを1行でWeb GUI化するライブラリを作った

はじめに

皆さん、CUI/CLIツールを使ってますか?
Qiitaを読んでるような人はみんな使ってるでしょうね。
しかし世間一般に視野を広げると、必ずしもそうではないかと思います。
『黒い画面はなんか敷居が高い』
『一応使えるけど面倒』
『信仰している宗教の戒律で固く禁じられている』
『黒い画面に故郷の村を焼かれた』
などなど理由は様々です。

黒画面.png

flagstone

使う側にとっては敷居の高いCUIツール。
とはいえGUIのツールを作るのは、我らがGo言語ではなかなかに面倒です。

そこで、Go言語製のCUIツールを1行でWeb GUI化するライブラリを作ってみました。

flagstone
https://github.com/kurehajime/flagstone

これです。
flagstoneは、日本語に訳すと『敷石』です。
舗装して歩きやすくしますよ〜みたいなネーミングです。

flagstone.png

使い方はとっても簡単。
例えば、こんなプログラムがあったとします。

package main

import (
    "flag"
    "fmt"
)

var who *string

func main() {
    who = flag.String("who", "world", "say hello to ...")
    flag.Parse()

    fmt.Println("hello " + *who + "!")
}

コマンドライン引数で受け取ったパラメータに文字を足して画面に表示するだけの簡単なプログラムですね。

これをコンソールから
./hello -who "世界"
と実行すると、
hello 世界!
と表示されるわけです。

これをflagstoneを使ってWeb GUI化していきましょう。

package main

import (
    "flag"
    "fmt"

    "github.com/kurehajime/flagstone" //★ ここと… ★
)

var who *string

func main() {
    who = flag.String("who", "world", "say hello to ...")
    flag.Parse()

    flagstone.Launch("helloworld", "flagstone sample") //★ ここを追記する! ★

    fmt.Println("hello " + *who + "!")
}

2行追加しました。
import句の"github.com/kurehajime/flagstone"
flag.Parse()のあとの
flagstone.Launch("helloworld", "flagstone sample")
の2行です。
タイトルは「1行でWeb GUI化する」と謳っていますが・・・import文はノーカンです。

これを実行するとどうなるでしょう。
こうなります。

スクリーンショット 2020-02-11 12.10.31.png

Web UIが出てきます。
実行ボタンと、パラメータの名前、入力欄、説明まで出てきます。
これは一番シンプルな例ですが、たくさんコマンドライン引数を受け取るプログラムでは、たくさん入力欄が出てきます。
テキストボックスに文字を入れて、Runボタンを押せばコマンドが実行されます。

付け足したのは実質

flagstone.Launch("helloworld", "flagstone sample")

この1行だけなのに、コマンドライン引数の欄まで作られてます。
なぜでしょうか。

この魔法はGo言語標準のflagパッケージにあります。
flagパッケージを使って定義されたコマンドライン引数はflagstoneで全部ぶっこ抜かれ、自動的にWeb UIが組み立てられます。
型のチェックまで行っているので、数字の入力欄に文字を入れると弾かれます。

完全にWebGUI化してしまうとコマンドラインツールとして使いたいときに不便なので、必須の引数を省略された際のフォールバックとしてのみ利用する使い方がおすすめです。

いくつかのオプションも用意しています。

中身

ここから先はflagstoneがどのように実装されているか解説していきます。

flag

Go言語のflagパッケージを使って指定されたコマンドライン引数は、flag.CommandLine.VisitAllを使うことで、コールバック形式でflagオブジェクトを取得できます。

flag.CommandLine.VisitAll(func(f *flag.Flag) {
    // fがflagオブジェクト
})

このflagオブジェクトは「Name」「DefValue」「Usage」でそれぞれ名前、初期値、説明文を取得できます。
f.Value.Set('hoge')と書けば、値のセットもでき、型に一致しない不適切な値がセットされた場合はerrorが返ります。

この機能を使えばflagの中身を全部ぶっこ抜けるわけです。

gowut

flagstoneのWeb UIはgowutというライブラリで実装しています。
これはコントロールの定義もイベント定義も全部Go言語で書けるWeb UIツールキットです。

公式のサンプルのソースはこんな感じです。
作り込めばこういうのも作れるようです。
デザインがイケてないと感じたら、任意のCSSやHTMLを挿入することもできます。

GoのGUIライブラリはまだ決定版と言えるものがなく、クロスプラットフォームに難があったり、コンパイルする際の敷居が高くなったりするものも多かったりします。
flagstoneはあくまで『オマケ』として利用されるものですので、足を引っ張らないことを重視してこれを選択しました。 1

おわりに

というわけで、Go言語製のCUIツールを1行でWeb GUI化するライブラリを作ってみました。
本格的なGUIアプリを作る労力をかけたくないけれど、CUIを使いたくない人にも裾野を広げたい場合などご利用ください。
まだ全然機能も貧弱ですので、プルリクも歓迎です。


  1. 最近npmでJavascriptのライブラリをインストールしようとした時、PythonとC++コンパイラが必須のライブラリが依存関係にあって色々面倒くさかったのが理由です。こいつのせいです。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Kubernetes】OperatorSDKにサクッと入門

概要

対象読者

  • 基本的なkubernetesの知識がある人
  • operatorとは何か、なんとなく把握しているが、開発を行なったことがない人
  • go言語の基本的な文法が読める人

はじめに

kubernetesの拡張機能の1つに、operatorが存在します。
operatorを利用すれば、運用の自動化を行うことができます。
operatorに関する詳しい説明は、下記リンクをご覧ください。
https://qiita.com/MahoTakara/items/af4ad8ab69c24102bd72

複数人で同一のclusterやnamespace上で開発を行なっている場合に、
誰がいつdeploymentのimageを変更したか分からず困る状況を想定し、
本記事では、deploymentのimageが変更されるたびに、slackに通知する仕組みを作成していきます。

なお、本記事で作成するものは、本来のoperator-sdkの使い方とは言えないため、
あくまでoperator-sdkに触れる目的であることをご留意ください。

環境構築

以下の環境が必要です。

  • go
  • operator-sdk
  • docker
  • kubectl

dockerやkubectlのインストールについては説明を省きます。
下記手順により、goおよびoperator-sdkをインストールします。

brew install go
go version # 筆者はv1.13.3を使用
export Go111MODULE=on # Go Modulesを使用するため
brew install operator-sdk
operator-sdk version # 筆者はv0.15.2を使用

また、kubernetesクラスタやdockerhub、slackapi(botによるメッセージ送信)が利用できる状態としてください。

開発

テンプレート生成

下記手順によりテンプレートを生成します。

operator-sdk new deployment-image-watcher --repo=github.com/<username>/deployment-image-watcher
cd deployment-image-watcher
operator-sdk add controller --api-version=deployment.k8s.io/v1alpha1 --kind=Deployment

通常、operator-sdkを使用する場合、CRD(Custom Resource Definition)を利用するのが一般的ですが、
今回はdeploymentのimageの変更を検知したいだけなので、CRDは生成しません。

controller

さっそく、根幹となるcontrollerを編集していきます。
controllerはpkg/controller/deployment/deployment_controller.goに存在します。
重要な部分は以下の通りです。
またファイル全体は https://github.com/solt9029/deployment-image-watcher/blob/master/pkg/controller/deployment/deployment_controller.go から確認できます。

func add(mgr manager.Manager, r reconcile.Reconciler) error {
    c, err := controller.New("deployment-controller", mgr, controller.Options{Reconciler: r})
    if err != nil {
        return err
    }

    slackClient := slack.New(os.Getenv("SLACK_TOKEN"))

    source := &source.Kind{Type: &appsv1.Deployment{}}
    handler := &handler.EnqueueRequestForObject{}
    predicate := predicate.Funcs{
        UpdateFunc: func(e event.UpdateEvent) bool {
            for _, oldContainer := range e.MetaOld.(*appsv1.Deployment).Spec.Template.Spec.Containers {
                for _, newContainer := range e.MetaNew.(*appsv1.Deployment).Spec.Template.Spec.Containers {
                    if oldContainer.Name == newContainer.Name && oldContainer.Image != newContainer.Image {
                        messageText := createMessage(newContainer.Name, newContainer.Image, oldContainer.Image)
                        slackClient.PostMessage(os.Getenv("SLACK_CHANNEL"), slack.MsgOptionText(messageText, true))
                    }
                }
            }
            return true
        },
    }

    err = c.Watch(source, handler, predicate)
    if err != nil {
        return err
    }

    return nil
}

watch関数のsourceの引数によって、監視対象としてdeploymentを設定します。
predicateは本来、deploymentの変更や追加、削除などのイベントに対して、
reconcileを行うべきかフィルタリングする役割を担っています。
このpredicate内では変更前の状態と変更後の状態を両方取得することができるため、
今回はこの部分でimageが変更されたかどうかを判定し、slack通知を行うロジックを書いています。

e.MetaOld.(*appsv1.Deployment).Spec.Template.Spec.Containers によって変更前のdeployment.spec.template.containersを取得できます。
同様に、変更後のdeployment.spec.template.containersも取得できます。
それらを用いて、imageを比較し、変更があればslack通知を行なっています。

ビルド

これだけで開発は終了です。
下記手順でビルドし、イメージをdocker registryにpushします。

operator-sdk build <username>/deployment-image-watcher:latest
docker push <username>/deployment-image-watcher:latest

マニフェスト

deploy/secret.yaml を追加し、以下のようなsecretのマニフェストを記述します。
SLACK_TOKEN にはslackapiのtokenをbase64化した値を入れてください。

echo -n "<your slack token>" | base64
apiVersion: v1
kind: Secret
metadata:
  name: deployment-image-watcher
type: Opaque
data:
  SLACK_TOKEN: <YOUR_SLACK_TOKEN_BASE64_ENCODED>

次に、deploy/operator.yaml を編集します。
以下の2つの環境変数を追加してください。

            - name: SLACK_TOKEN
              valueFrom:
                secretKeyRef:
                  name: deployment-image-watcher
                  key: SLACK_TOKEN
            - name: SLACK_CHANNEL
              value: "general"

動作確認

下記手順により、deployment-image-watcherをデプロイします。

kubectl apply -f deploy/

なんらかのdeploymentをapplyし、imageを変更してみてください。
slackに通知が届くはずです。

おわりに

本記事では、operator-sdkを利用して、deploymentのimageが変更されるたびに、slackに通知する仕組みを作成しました。
operator-sdkを手軽に使うために、CRDを用いずに簡易的なサンプルを実装しました。
本来のoperator-sdkの利用目的とは若干ずれていましたが、本記事によって基本的な使い方がわかれば幸いです。
ありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Go] ゴブレットゴブラーズの通信ゲームを作ってみた

はじめに

ガキ使でゴブレットゴブラーズというボードゲームを紹介していてとても面白そうだったので、Goで作ってみることにしました。

ゴブレットゴブラーズについては以下の記事がわかりやすかったです!
https://kyoheiomi.com/board-game/recommendation/gobblet-gobblers

完成品

画像がないです。

機能

  • ルーム作成
  • 通信対戦
  • 閲覧機能

構成

server-client型で作りました。
serverに対して、clientがポーリングを行いゲームを更新していきます。
インターフェースはjsonを用いています。
以下はパッケージ構成です。

├── cli // ゲームを実行するcliツール群です。
│   ├── cli.go
│   └── util
│       ├── app.go
│       ├── client.go
│       ├── control.go
│       ├── display.go
│       ├── display_util.go
│       ├── model.go
│       ├── screen.go
│       └── util.go
├── go.mod
├── go.sum
├── logic //ゲームのロジックをまとめたところです。
│   ├── board.go
│   ├── game.go
│   ├── piece.go
│   ├── player.go
│   ├── square.go
│   └── type.go
├── server // logicを使って、サーバを立てています
│   ├── handler.go
│   ├── model.go
│   └── server.go
└── web //clientがWebの場合も作る:未実装

logicとserverを分けた理由

  • 今後、インターフェースを変更する場合があると、インターフェースとゲームロジックをすぐに切り分けできるようにするためです。
  • logicで用いているモデルをcliでも利用できるためです。

実装説明

少し実装を説明します。

const P1 P = 1
const P2 P = -1

type Piece struct {
    id   uint
    size Size
    user P
}
type Square struct {
    top    int
    pieces [3]*Piece
}  
type Board [BOARD_MAX][BOARD_MAX]*Square

Pieceには、大きさとユーザ情報を持たせています。
Squareはマスのことで、マスにはコマを最大3つまで置くことができるため、マスの状態を順番ありで保持しておく必要があります。
Boardは、このマスが指定した個数あります。
スライスでなく、配列を用いることで、想定外の処理はpanicになるようにしています。
これらにメソッドを生やしゲームロジックを作成します。
細かいコードは、以下をご覧ください。

ゲームの使い方

  1. serverを立ち上げる
    $ go run server/*.go
  2. ユーザ1が部屋を作成する

    $ go run cli/cli.go -me tida -op yuna
    meオプションが自分の名前,opオプションが相手の名前を入力します。
    すると、ルームIDが払い出されます。(ex a48dec12-2a25-4b61-ad60-95134fd93b24)

  3. ユーザ2が部屋に参加する

    $ go run cli/cli.go -me yuna -room a48dec12-2a25-4b61-ad60-95134fd93b24
    ユーザ1が作成した部屋のルームIDと自分のユーザネームを入力します。
    すると、ゲームが始まります。
    ちなみに、meオプションで設定した名前と部屋が作成された時に登録された名前が一致しない場合、閲覧者としてゲームをみることができます。

  4. ゲーム
    ターン毎にターミナルにコマの配置をしていきます。
    ``` a,A,2(a,Aマスに大きさ2のコマを置く)

    未実装

    WEB版

    今回はtermboxを使いたく、cliを使いましたが、見た目が拙いです。
    ブラウザでもできるようにしたいです。WebAssemblyを使うと、logicのモデルを再利用できるので、便利かもしれないです。
    【Go】WebAssemblyでtrend表示してみた

    エラーハンドリング

    cliのエラーハンドリングが甘いです。

    メモリ管理

    ゲームが終了した後、ゲーム情報を削除していないので、常に残り続けます。

    その他もろもろ

    サービスとして提供するには、例外も含め考慮する点がまだまだアリそうです。

最後に

ゲーム作成は、例外が多く存在するため、考慮すべき点が多くて大変でした。
既存実装の追加改修してくれる人は、ぜひプルリクお願いいたしますmm

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CI/CDハンズオン

AWS CI/CDハンズオン

今回は細かな用語の説明などは飛ばして、基本的にCI/CDを体感するためのとりあえず手を動かすという内容となっておりますので、15分程度で実践することができると思います。

用語説明

継続的インテグレーション(CI)とは

開発者が自分のコード変更を定期的にセントラルリポジトリにマージし、その後に自動化されたビルドとテストを実行するDevOpsソフトウェア開発の手法のことです。
メリットとして、テストが頻繁に行われる。それによって、バグの発見にかかる時間が削減されます。また、機械的なチェックなどを自動化することができるので、開発者はアプリケーションの本質的なことに集中できるのです。

継続的デリバリ(CD)とは

ソフトウェア開発手法の一つで、コード変更が発生すると、自動的に実稼働環境へのリリース準備が実行されるというものです。継続的デリバリーは継続的インテグレーションを拡張したものです。
メリットとして、デプロイまでのリリースが自動化されることです。それによって、コードの変更を素早くリリース可能となります。

登場人物

CodePipeline

マネージドな継続的デリバリサービスです。

AWS環境にデプロイするパイプラインを容易に構築できます。

CodeBuild

マネージドなビルドを行うサービスです。

CodeDeploy

マネージドな自動デプロイサービスです。

全体の構成

『Githubのmasterブランチへのコミットをトリガーにソースコードを取得(CodePipelineでの処理を開始)→CodeBuildでのビルド開始→CodeDeployのデプロイ開始』という流れとなっております。
スクリーンショット 2020-02-16 2.10.12.png

実践

Githubリポジトリの準備

デプロイするソースコード自体はなんでも良いのですが、今回はGolangのソースコードを用意しておきました。こちらのソースコードを使用して頂いても、独自のソースコードを使用して頂いても構いません。(独自ソースコードや異なる言語で作成する場合は、buildspec.ymlファイルを修正する必要があります。)

デプロイ対象となるEC2やVPCの準備

今回、EC2やVPCはハンズオンのメインではないので、cloudformation.yamlというファイルを作成しておきました。こちらはAWSの infrastructure as codeにあたるもので、簡単に環境を構築できるようにしておきました。以下の手順に従ってCloudFormationを流してください。

  1. AWSマネジメントコンソールにログインし(東京リージョン)、EC2サービスを選択する。
  2. 左側の一覧から、キーペアを選択する。

スクリーンショット 2020-02-16 1.02.51.png
3. キーペアの作成から、Name: HandsonSampleKey, FileFormat: pemで作成する(CloudFormationの記述と結びついているので、違う名前にしたければ、CloudFormationでHandsonSampleKeyとなっている点を任意の名前に変更する)。
スクリーンショット 2020-02-16 1.03.18.png
4. CloudFormationサービスを選択する。
5. スタックの作成→新しいリソースを使用(標準)を選択する。
6. 以下の画像のように選択をし、Golangのソースコードのリポジトリに含まれるcloudformation.yamlファイルを選択する。
スクリーンショット 2020-02-16 0.57.48.png
7. 以下の画像のようにスタックの名前: Handsonと入力し、次へ進む。
スクリーンショット 2020-02-16 0.58.26.png
8. スタックオプションの設定とレビューは特に指定しなくて良いので、レビューまで進む。
9. 最後に以下の画像のようにチェックボックスのチェックを行い、スタックの作成を行う。
スクリーンショット 2020-02-16 0.58.56.png
10. 以下の画像のようにCREATE_COMPLETEとなれば終了である。
スクリーンショット 2020-02-16 1.07.30.png
11. EC2のIPv4パブリックIPにアクセスし、Nginxが起動しているか確認する。
スクリーンショット 2020-02-16 1.09.25.png
スクリーンショット 2020-02-16 1.09.46.png

今回のハンズオンのメイン

CodeDeploy作成

  1. CodeDeployサービスを選択し、アプリケーションの作成を選択する。
  2. 以下の画像のように入力し、作成を選択する。

スクリーンショット 2020-02-16 1.11.24.png
3. 成功画面が表示されると、そのままデプロイグループの作成を選択する。
スクリーンショット 2020-02-16 1.11.36.png
4. 以下の画像のように入力し、作成を選択する。
スクリーンショット 2020-02-16 1.12.30.png
スクリーンショット 2020-02-16 1.40.55.png
スクリーンショット 2020-02-16 1.14.11.png

CodePipelineの作成

  1. CodePipelineサービスを選択し、パイプラインの作成を選択する。
  2. 以下の画像のように入力し、次にを選択する。

スクリーンショット 2020-02-16 1.16.31.png
3. ソースプロバイダとして以下の画像のようにソースコード引っ張ってきたい場所を選択する。(リポジトリやブランチは自分のものを選択してください。この時、リポジトリやブランチに選択肢が表示されるまで少し時間がかかると思います。)
スクリーンショット 2020-02-16 1.31.46.png
4. CodeBuildの設定を行います。以下の画像のように選択し、プロジェクトを作成するを選択します。
スクリーンショット 2020-02-16 1.32.00.png
5. 以下の画像のように入力・選択を行い、CodePipelineに進むを選択する。
スクリーンショット 2020-02-16 1.33.11.png
スクリーンショット 2020-02-16 1.33.44.png
スクリーンショット 2020-02-16 1.33.57.png
6. デプロイステージの追加では、前項で作成したCodeDeployを使用します。以下の画像のように入力・選択を行う。
スクリーンショット 2020-02-16 1.34.22.png
7. 以上で全ての設定が終了したので、作成ボタンを押します。
8. 正常に終了していれば、以下の画像のようにCodePipelineが稼働します。
スクリーンショット 2020-02-16 1.34.36.png
9. CodePipelineが全て終了後(5分程度)、EC2のエンドポイント(IP)に、IPアドレス:8080/ping/jsonとアクセスすると、以下の画像のようにレスポンスが返ってくると成功です。

スクリーンショット 2020-02-16 1.49.06.png

まとめ

今回は、とりあえず手を動かしてCI/CDを体感したい人向けに、細かな用語等は説明しませんでしたが、少しでも作り込みたい(appspec.ymlbuildspec.ymlなど)となった時に、必ず細かな知識等も必要になってきますので、そこは別記事等で学ぶことをお勧めします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Go】構造体サンプルメモ

サンプル

package main

import "fmt"

type Person struct {
    name string
    age int
}

func main() {
    // 宣言の後、値を代入
    var person1 Person
    person1.name = "Akira"
    person1.age = 20
    fmt.Println(person1)

    // 宣言+代入
    person2 := Person{age: 30, name: "Kure"}
    fmt.Println(person2)

    // 宣言+代入
    person3 := Person{"Aki", 40}
    fmt.Println(person3)
}
package main

import (
    "fmt"
    "encoding/json"
)

func main() {
    type location struct {
        Name string
        Lat float64
        Long float64
    }

    // JSON 変換するためにキーを大文字にしておく必要がある
    locations := []location {
        {Name: "Brandbury Landing", Lat: -4.5895, Long: 137.4417},
        {Name: "Columbia Memorial Station", Lat: -14.56684, Long: 175.472636},
        {Name: "Challenger Memorial Station", Lat: -1.9462, Long: 354.4734},
    }

    // [{Brandbury Landing -4.5895 137.4417} {Columbia Memorial Station -14.56684 175.472636} {Challenger Memorial Station -1.9462 354.4734}]
    fmt.Println(locations)

    b, _ := json.Marshal(locations)
    // [{"Name":"Brandbury Landing","Lat":-4.5895,"Long":137.4417},{"Name":"Columbia Memorial Station","Lat":-14.56684,"Long":175.472636},{"Name":"Challenger Memorial Station","Lat":-1.9462,"Long":354.4734}]
    fmt.Println(string(b))

    // JSONキーを指定
    type location2 struct {
        Name string `json:"name"`
        Lat float64 `json:"lat"`
        Long float64 `json:"long"`
    }

    locations2 := []location2 {
        {Name: "Brandbury Landing", Lat: -4.5895, Long: 137.4417},
        {Name: "Columbia Memorial Station", Lat: -14.56684, Long: 175.472636},
        {Name: "Challenger Memorial Station", Lat: -1.9462, Long: 354.4734},
    }

    // [{Brandbury Landing -4.5895 137.4417} {Columbia Memorial Station -14.56684 175.472636} {Challenger Memorial Station -1.9462 354.4734}]
    fmt.Println(locations2)

    c, _ := json.MarshalIndent(locations2, "", "  ")
  //    [
  //  {
  //    "name": "Brandbury Landing",
  //    "lat": -4.5895,
  //    "long": 137.4417
  //  },
  //  {
  //    "name": "Columbia Memorial Station",
  //    "lat": -14.56684,
  //    "long": 175.472636
  //  },
  //  {
  //    "name": "Challenger Memorial Station",
  //    "lat": -1.9462,
  //    "long": 354.4734
  //  }
  //]
    fmt.Println(string(c))
}

参考

改訂2版 基礎からわかる Go言語
古川 昇
シーアンドアール研究所 (2015-07-17)
売り上げランキング: 201,077
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

良さげなクロスプラットフォーム開発向け言語《v》のメモ(Go,Nim,Rustと少し比較)

GoとNimは趣味でそれなりに触って、Rustは仕事にならない限り触らないことにしている自分が、v言語をチラ見してみたのでメモを残しておく。 バージョン0.1台とまだまだ若い言語なので参考程度に。
v言語:
https://vlang.io/

v言語を三行で

  • v言語はGoをリスペクトしてる型あり言語。もともとvはGoで書かれていた。
  • Nimと同様にC言語をバックエンドとしてバイナリ化する。vは、Nim並みにコンパイルは早くバイナリサイズは小さく。
  • Rustとは異なり言語仕様はシンプルに。モダンなところはRustにも学ぶ(関数定義はfuncではなくfnだし...)。

v言語の使い所、思ったところを三行で

  • 公式サイトとしては、v言語をクロスプラットフォームなクライアント側のアプリ作りに使って欲しい模様。出自からも当座はクライアント側一択か。
  • 実用するには、C/C++(/objective-C)との相性の良さが、「実績として」活かされるようになることが必要か。
  • サーバ側とのやり取りはjsonで行うのが基本か。近い将来のモダンな開発としてはサーバ側はGraphQLでインターフェイスを切るといったところになるのだろう。

どこぞの猛者がネットワークゲームのクライアントとしてv言語を採用してくださったりすると、v言語が広まるのだろうか。

見た目。好感あり。

GoっぽいがRustっぽくもあるのだろう。が、Rustを良く知らないので、とりあえず、Scalaを日常的に書いている人間としては違和感が少なくて良かった。まぁ、vはモダンな見た目の言語ということ。チラ見しておこう。

#公式サイトに行くと、web上でv言語のサンプルを実行することができる。web上での実行は若い言語では望ましい機能だね。

①文字列の扱い

name := 'Bob'
println('Hello, $name!')  // `$` is used for string interpolation
println(name.len)

bobby := name + 'by' // + is used to concatenate strings
println(bobby) // "Bobby" 

println(bobby[1..3]) // "ob" 
mut s := 'hello '
s += 'world' // `+=` is used to append to a string
println(s) // "hello world" 

やはりGoっぽい。文字列をmutableな場合にはmutで明示するというあたりは今風で良い(scala/kotlin等のval/var相当)。

出典:
https://vlang.io/docs#strings

②パターンマッチ

s := match number {
    1    { 'one' }
    2    { 'two' }
    else { 
        println('this works too')
        'many' 
    }
}

出典:
https://vlang.io/docs#match

scalaのmatch(以下)と近しいね。

val s = number match  {
    case 1 =>   'one'
    case 2 =>   'two'
    case _ => { 
        println('this works too')
        'many' 
    }
}

③高階関数

かなりGoっぽいね。

fn sqr(n int) int {
        return n * n
}

fn run(value int, op fn(int) int) int {
        return op(value)
}

fn main()  {
        println(run(5, sqr)) // "25"
}

出典:
https://vlang.io/docs#highfns

参考
Go言語で高階関数を書いて遊んでみた

④インターフェイス

こちらもGoっぽいね。ただ、コンパイルが通らなかった。まぁ、若い言語ですから ;-)

struct Dog {}
struct Cat {}

fn (d Dog) speak() string {
    return 'woof'
}

fn (c Cat) speak() string {
    return 'meow' 
}

interface Speaker {
    speak() string
}

fn perform(s Speaker) {
    println(s.speak())
}

dog := Dog{}
cat := Cat{}
perform(dog) // "woof" 
perform(cat) // "meow" 

出典:
https://vlang.io/docs#interfaces

参考
Goのinterfaceがわからない人へ

⑤テスト手法

hello.vをテストする際には、hello_test.vを用意してね、とのこと。

hello.v
fn hello() string {
    return 'Hello world'
}
hello_test.v
fn test_hello() {
    assert hello() == 'Hello world'
}

まぁ、実際に開発する段になってから考えるところだろうけど、IDEがサポートしてくれたら使いやすいのかも。

感想

Swift/Kotlinが結局クロスプラットフォーム開発用途には不十分と思われるので、ニッチなクロスプラットフォーム開発用途ではv言語ありかも。nimとの比較は気が向いた時にでも。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

良さげなクロスプラットフォーム開発言語《v》のメモ(Go,Nim,Rustと少し比較)

GoとNimは趣味でそれなりに触って、Rustは仕事にならない限り触らないことにしている自分が、v言語をチラ見してみたのでメモを残しておく。 バージョン0.1台とまだまだ若い言語なので参考程度に。
v言語:
https://vlang.io/

cf.なるほど。
Rustを業務で1年使ってみてわかったこと

v言語を三行で

  • v言語はGoをリスペクトしてる型あり言語。もともとvはGoで書かれていた。
  • Nimと同様にC言語をバックエンドとしてバイナリ化する。vは、Nim並みにコンパイルは早くバイナリサイズは小さく。
  • Rustとは異なり言語仕様はシンプルに。モダンなところはRustにも学ぶ(関数定義はfuncではなくfnだし...)。

v言語の使い所、思ったところを三行で

  • 公式サイトとしては、v言語をクロスプラットフォームなクライアント側のアプリ作りに使って欲しい模様。出自からも当座はクライアント側一択か。
  • 実用するには、C/C++(/objective-C)との相性の良さが、「実績として」活かされるようになることが必要か。
  • サーバ側とのやり取りはjsonで行うのが基本か。近い将来のモダンな開発としてはサーバ側はGraphQLでインターフェイスを切るといったところになるのだろう。

どこぞの猛者がネットワークゲームのクライアントとしてv言語を採用してくださったりすると、v言語が広まるのだろうか。

見た目。学習コストが低そうで好感あり。

GoっぽいがRustっぽくもあるのだろう。が、Rustを良く知らないので、とりあえず、Scalaを日常的に書いている人間としては違和感が少なくて良かった。まぁ、vはモダンな見た目の言語ということ。チラ見しておこう。

#公式サイトに行くと、web上でv言語のサンプルを実行することができる。web上での実行は若い言語では望ましい機能だね。

①文字列の扱い

name := 'Bob'
println('Hello, $name!')  // `$` is used for string interpolation
println(name.len)

bobby := name + 'by' // + is used to concatenate strings
println(bobby) // "Bobby" 

println(bobby[1..3]) // "ob" 
mut s := 'hello '
s += 'world' // `+=` is used to append to a string
println(s) // "hello world" 

やはりGoっぽい。文字列をmutableで扱う場合にはmutで明示するというあたりは今風で良い(scala/kotlin等のval/var相当)。

出典:
https://vlang.io/docs#strings

②パターンマッチ

s := match number {
    1    { 'one' }
    2    { 'two' }
    else { 
        println('this works too')
        'many' 
    }
}

出典:
https://vlang.io/docs#match

scalaのmatch(以下)と近しい。

val s = number match  {
    case 1 =>   'one'
    case 2 =>   'two'
    case _ => { 
        println('this works too')
        'many' 
    }
}

③高階関数

かなりGoっぽいね。

fn sqr(n int) int {
        return n * n
}

fn run(value int, op fn(int) int) int {
        return op(value)
}

fn main()  {
        println(run(5, sqr)) // "25"
}

出典:
https://vlang.io/docs#highfns

参考
Go言語で高階関数を書いて遊んでみた

④インターフェイス

こちらもGoっぽい。ただ、コンパイルが通らなかった。まぁ、若い言語ですから ;-)

struct Dog {}
struct Cat {}

fn (d Dog) speak() string {
    return 'woof'
}

fn (c Cat) speak() string {
    return 'meow' 
}

interface Speaker {
    speak() string
}

fn perform(s Speaker) {
    println(s.speak())
}

dog := Dog{}
cat := Cat{}
perform(dog) // "woof" 
perform(cat) // "meow" 

出典:
https://vlang.io/docs#interfaces

参考
Goのinterfaceがわからない人へ

⑤テスト手法

hello.vをテストする際には、hello_test.vを用意してね、とのこと。

hello.v
fn hello() string {
    return 'Hello world'
}
hello_test.v
fn test_hello() {
    assert hello() == 'Hello world'
}

まぁ、実際に開発する段になってから考えるところだろうけど、IDEがサポートしてくれたら使いやすいのかも。

感想

Swift/Kotlinが結局クロスプラットフォーム開発用途には不十分と思われるので、ニッチなクロスプラットフォーム開発用途ではv言語ありかも。nimとの比較は気が向いた時にでも。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む