- 投稿日:2020-02-16T22:45:26+09:00
Go言語製のCUIツールを1行でWeb GUI化するライブラリを作った
はじめに
皆さん、CUI/CLIツールを使ってますか?
Qiitaを読んでるような人はみんな使ってるでしょうね。
しかし世間一般に視野を広げると、必ずしもそうではないかと思います。
『黒い画面はなんか敷居が高い』
『一応使えるけど面倒』
『信仰している宗教の戒律で固く禁じられている』
『黒い画面に故郷の村を焼かれた』
などなど理由は様々です。flagstone
使う側にとっては敷居の高いCUIツール。
とはいえGUIのツールを作るのは、我らがGo言語ではなかなかに面倒です。そこで、Go言語製のCUIツールを1行でWeb GUI化するライブラリを作ってみました。
flagstone
https://github.com/kurehajime/flagstoneこれです。
flagstoneは、日本語に訳すと『敷石』です。
舗装して歩きやすくしますよ〜みたいなネーミングです。使い方はとっても簡単。
例えば、こんなプログラムがあったとします。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文はノーカンです。これを実行するとどうなるでしょう。
こうなります。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を使いたくない人にも裾野を広げたい場合などご利用ください。
まだ全然機能も貧弱ですので、プルリクも歓迎です。
- 投稿日:2020-02-16T20:55:14+09:00
【Kubernetes】OperatorSDKにサクッと入門
概要
- 本記事では、operator-sdkを利用して、deploymentのimageが変更されるたびに、slackに通知する仕組みを作成します。
- サンプルコード: https://github.com/solt9029/deployment-image-watcher
- 挙動: https://www.youtube.com/watch?v=eknVJj8E-HE&feature=youtu.be
対象読者
- 基本的な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>" | base64apiVersion: 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の利用目的とは若干ずれていましたが、本記事によって基本的な使い方がわかれば幸いです。
ありがとうございました。
- 投稿日:2020-02-16T16:04:16+09:00
[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]*SquarePieceには、大きさとユーザ情報を持たせています。
Squareはマスのことで、マスにはコマを最大3つまで置くことができるため、マスの状態を順番ありで保持しておく必要があります。
Boardは、このマスが指定した個数あります。
スライスでなく、配列を用いることで、想定外の処理はpanicになるようにしています。
これらにメソッドを生やしゲームロジックを作成します。
細かいコードは、以下をご覧ください。
ゲームの使い方
- serverを立ち上げる
$ go run server/*.go
ユーザ1が部屋を作成する
$ go run cli/cli.go -me tida -op yuna
meオプションが自分の名前,opオプションが相手の名前を入力します。
すると、ルームIDが払い出されます。(ex a48dec12-2a25-4b61-ad60-95134fd93b24)ユーザ2が部屋に参加する
$ go run cli/cli.go -me yuna -room a48dec12-2a25-4b61-ad60-95134fd93b24
ユーザ1が作成した部屋のルームIDと自分のユーザネームを入力します。
すると、ゲームが始まります。
ちなみに、meオプションで設定した名前と部屋が作成された時に登録された名前が一致しない場合、閲覧者としてゲームをみることができます。ゲーム
ターン毎にターミナルにコマの配置をしていきます。
``` a,A,2(a,Aマスに大きさ2のコマを置く)未実装
WEB版
今回はtermboxを使いたく、cliを使いましたが、見た目が拙いです。
ブラウザでもできるようにしたいです。WebAssemblyを使うと、logicのモデルを再利用できるので、便利かもしれないです。
【Go】WebAssemblyでtrend表示してみたエラーハンドリング
cliのエラーハンドリングが甘いです。
メモリ管理
ゲームが終了した後、ゲーム情報を削除していないので、常に残り続けます。
その他もろもろ
サービスとして提供するには、例外も含め考慮する点がまだまだアリそうです。
最後に
ゲーム作成は、例外が多く存在するため、考慮すべき点が多くて大変でした。
既存実装の追加改修してくれる人は、ぜひプルリクお願いいたしますmm
- 投稿日:2020-02-16T12:03:55+09:00
AWS CI/CDハンズオン
AWS CI/CDハンズオン
今回は細かな用語の説明などは飛ばして、基本的にCI/CDを体感するためのとりあえず手を動かすという内容となっておりますので、15分程度で実践することができると思います。
用語説明
継続的インテグレーション(CI)とは
開発者が自分のコード変更を定期的にセントラルリポジトリにマージし、その後に自動化されたビルドとテストを実行するDevOpsソフトウェア開発の手法のことです。
メリットとして、テストが頻繁に行われる。それによって、バグの発見にかかる時間が削減されます。また、機械的なチェックなどを自動化することができるので、開発者はアプリケーションの本質的なことに集中できるのです。継続的デリバリ(CD)とは
ソフトウェア開発手法の一つで、コード変更が発生すると、自動的に実稼働環境へのリリース準備が実行されるというものです。継続的デリバリーは継続的インテグレーションを拡張したものです。
メリットとして、デプロイまでのリリースが自動化されることです。それによって、コードの変更を素早くリリース可能となります。登場人物
CodePipeline
AWS環境にデプロイするパイプラインを容易に構築できます。
CodeBuild
CodeDeploy
全体の構成
『Githubのmasterブランチへのコミットをトリガーにソースコードを取得(CodePipelineでの処理を開始)→CodeBuildでのビルド開始→CodeDeployのデプロイ開始』という流れとなっております。
実践
Githubリポジトリの準備
デプロイするソースコード自体はなんでも良いのですが、今回はGolangのソースコードを用意しておきました。こちらのソースコードを使用して頂いても、独自のソースコードを使用して頂いても構いません。(独自ソースコードや異なる言語で作成する場合は、
buildspec.yml
ファイルを修正する必要があります。)デプロイ対象となるEC2やVPCの準備
今回、EC2やVPCはハンズオンのメインではないので、
cloudformation.yaml
というファイルを作成しておきました。こちらはAWSの infrastructure as codeにあたるもので、簡単に環境を構築できるようにしておきました。以下の手順に従ってCloudFormationを流してください。
- AWSマネジメントコンソールにログインし(東京リージョン)、EC2サービスを選択する。
- 左側の一覧から、キーペアを選択する。
3. キーペアの作成から、Name: HandsonSampleKey
,FileFormat: pem
で作成する(CloudFormationの記述と結びついているので、違う名前にしたければ、CloudFormationでHandsonSampleKey
となっている点を任意の名前に変更する)。
4. CloudFormationサービスを選択する。
5. スタックの作成→新しいリソースを使用(標準)を選択する。
6. 以下の画像のように選択をし、Golangのソースコードのリポジトリに含まれるcloudformation.yaml
ファイルを選択する。
7. 以下の画像のようにスタックの名前: Handson
と入力し、次へ進む。
8. スタックオプションの設定とレビューは特に指定しなくて良いので、レビューまで進む。
9. 最後に以下の画像のようにチェックボックスのチェックを行い、スタックの作成を行う。
10. 以下の画像のようにCREATE_COMPLETEとなれば終了である。
11. EC2のIPv4パブリックIPにアクセスし、Nginxが起動しているか確認する。
今回のハンズオンのメイン
CodeDeploy作成
- CodeDeployサービスを選択し、アプリケーションの作成を選択する。
- 以下の画像のように入力し、作成を選択する。
3. 成功画面が表示されると、そのままデプロイグループの作成を選択する。
4. 以下の画像のように入力し、作成を選択する。
CodePipelineの作成
- CodePipelineサービスを選択し、パイプラインの作成を選択する。
- 以下の画像のように入力し、次にを選択する。
3. ソースプロバイダとして以下の画像のようにソースコード引っ張ってきたい場所を選択する。(リポジトリやブランチは自分のものを選択してください。この時、リポジトリやブランチに選択肢が表示されるまで少し時間がかかると思います。)
4. CodeBuildの設定を行います。以下の画像のように選択し、プロジェクトを作成するを選択します。
5. 以下の画像のように入力・選択を行い、CodePipelineに進むを選択する。
6. デプロイステージの追加では、前項で作成したCodeDeployを使用します。以下の画像のように入力・選択を行う。
7. 以上で全ての設定が終了したので、作成ボタンを押します。
8. 正常に終了していれば、以下の画像のようにCodePipelineが稼働します。
9. CodePipelineが全て終了後(5分程度)、EC2のエンドポイント(IP)に、IPアドレス:8080/ping/json
とアクセスすると、以下の画像のようにレスポンスが返ってくると成功です。まとめ
今回は、とりあえず手を動かしてCI/CDを体感したい人向けに、細かな用語等は説明しませんでしたが、少しでも作り込みたい(appspec.ymlやbuildspec.ymlなど)となった時に、必ず細かな知識等も必要になってきますので、そこは別記事等で学ぶことをお勧めします。
- 投稿日:2020-02-16T00:38:23+09:00
【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言語posted with amazlet at 20.02.15古川 昇
シーアンドアール研究所 (2015-07-17)
売り上げランキング: 201,077
- 投稿日:2020-02-16T00:20:17+09:00
良さげなクロスプラットフォーム開発向け言語《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#matchscalaの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っぽいね。ただ、コンパイルが通らなかった。まぁ、若い言語ですから ;-)
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⑤テスト手法
hello.v
をテストする際には、hello_test.v
を用意してね、とのこと。hello.vfn hello() string { return 'Hello world' }hello_test.vfn test_hello() { assert hello() == 'Hello world' }まぁ、実際に開発する段になってから考えるところだろうけど、IDEがサポートしてくれたら使いやすいのかも。
感想
Swift/Kotlinが結局クロスプラットフォーム開発用途には不十分と思われるので、ニッチなクロスプラットフォーム開発用途ではv言語ありかも。nimとの比較は気が向いた時にでも。
- 投稿日:2020-02-16T00:20:17+09:00
良さげなクロスプラットフォーム開発言語《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#matchscalaの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っぽい。ただ、コンパイルが通らなかった。まぁ、若い言語ですから ;-)
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⑤テスト手法
hello.v
をテストする際には、hello_test.v
を用意してね、とのこと。hello.vfn hello() string { return 'Hello world' }hello_test.vfn test_hello() { assert hello() == 'Hello world' }まぁ、実際に開発する段になってから考えるところだろうけど、IDEがサポートしてくれたら使いやすいのかも。
感想
Swift/Kotlinが結局クロスプラットフォーム開発用途には不十分と思われるので、ニッチなクロスプラットフォーム開発用途ではv言語ありかも。nimとの比較は気が向いた時にでも。