mattn
mattn
タンブラー?
2K posts
Big Sky
Don't wanna be here? Send us removal request.
mattn · 5 years ago
Text
プログラマーのための新しい情報共有コミュニティ Zenn で本を書いてみた。
先日、vim-jp の Slack で zenn という情報コミュニティを知りました。
Zenn|プログラマーのための情報共有コミュニティ
Publish your book Zennではウェブ上で読める本を投稿することができます。本は無料公開も、有料販売もできます。 あなたが得意な技術やアイデアを、ぜひ1冊の本にまとめてみましょう。 本...
https://zenn.dev
Qiita と Note を足して2で割った様なサービスで、Markdown で記事や本を執筆する事ができます。有料の記事や本を執筆する事もできます。また有料でなくても記事を読んでサポートしたいと思う方がいれば寄付という形で還元頂ける仕組みがあります。
先日、ActixWeb という Rust のウェブフレームワークにパッチを送った話を zenn に投稿した所、1000 円のサポートを受けました。モチベーションもあがって良いですね。
ActixWeb にパッチを送った話 | Zenn
はじめに 先日、ActixWeb にパッチを送りました。とは言っても本体ではなく examples の中に格納されている todo アプリの話。 https://ift.tt/32QTrrj...
https://ift.tt/3iDnB6V
Note はアカウントは持ってはもっていつつも一度も書いた事がなかったのですが、zenn は CLI も用意されていてプログラマが技術情報を公開してサポートを受けるには良いプラットフォームだと感じました。試しに zenn で有料の本を書いてみました。少し実験してみたいという気持ちもありました。
Go 言語にやってくる Generics は我々に何をもたらすのか | Zenn
2021 年リリース予定の Go 1.17 に、多くの皆さんが待ち望んでいた Generics が導入される予定です。Go が Generics を採用したプロセス、C++ や Java の Gene...
https://ift.tt/3cjvcFf
価格設定は超適当に 1000 字 50 円と考えました。(13000~14000字くらいなので600円)
2020年9月22日の午前3時に公開したので、およそ9時間くらいですが 22000 円程度の売り上げがあります。何か本を書いてみたいけど技術書店に出す勇気は無い、または時間がない、でも皆に読んで欲しい、そういった方々でも簡単に出版できる zenn はとても良いサービスだと思いました。ウェブ上のエディタに少し難がありますが、それはいずれ修正されると思います。またローカルでテキストエディタを使って編集する方法も提供されています。本を出版する際のセクションの分け方ははじめ少し戸惑いますが、しばらく触っていれば慣れると思います。またどこを無料にしてどこを有料にするかの設定も可能なので、チラ見せも出来る様になっています。皆さんもフォルダの奥に眠っている素晴らしい駄文を本にしてみては如何でしょうか。
from Big Sky https://ift.tt/32R3z3p
1 note · View note
mattn · 5 years ago
Text
os/signal に NotifyContext が入った。
Go のアプリケーションを作っていると、シグナルの受信に伴い処理を中断したり再起動する処理を実装する事が多い。これまでは signal.Notify でシグナルをキャッチし、別途 context.WithCancel で作成したコンテキストを自ら cancel する処理を書かなければならなかった。Go の tip に入ったコミットにより、これが幾分改善される様になった。
package main import (     "context"     "fmt"     "os"     "os/signal"     "time" ) func main() {     ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)     defer stop()     select {     case <-time.After(time.Second):         fmt.Println("done")     case <-ctx.Done():         stop()         fmt.Println("canceled")     } }
このコードを実行すると、1秒経過すると done が、途中で CTRL-C をタイプすると canceled が表示される。一見、利用用途が少ない様に見えるが以下の様に goroutine を複数起動し、signal で一括終了する時には便利。
package main import (     "context"     "fmt"     "os"     "os/signal"     "sync" ) func blocking(ctx context.Context, wg *sync.WaitGroup) {     defer wg.Done()     fmt.Println("worker started")     <-ctx.Done()     fmt.Println("worker canceled") } func main() {     ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)     defer stop()     var wg sync.WaitGroup     wg.Add(3)     go blocking(ctx, &wg)     go blocking(ctx, &wg)     go blocking(ctx, &wg)     wg.Wait() }
from Big Sky https://ift.tt/3kfeQQG
1 note · View note
mattn · 5 years ago
Text
Windows ユーザは cmd.exe で生きるべき 2020年版
はじめに
2016年にこんな記事を書きました。
Big Sky :: Windows ユーザは cmd.exe で生きるべき。
[D] Windowsはターミナルがダメだから使えないってのは過去の話? 基本的にはいい感じに見えますが、いくつか問題は発覚してます。 https://ift.tt/3eNjSk9...
https://ift.tt/2vBxeuK
この記事は日常からコマンドプロンプトを使うユーザに Windows で生き抜く為の僕なりの方法を教授したつもりです。最近は PowerShell を使われる方も多いと思いますが、僕はどうしても PowerShell が好きになれず、未だにコマンドプロンプトで生き続けています。
あれから4年
記事の反響は結構大きく、いろいろなコメントも頂きました。あれから幾らかこのハック方法をアップデートしてきたので、この記事で紹介したいと思います。前の記事では、こんな事を言っていました。
コマンドインから groovy を使った開発を行いたい場合は、まずこのバッチファイル(groovyenv.bat という名前にしています)を実行します。
この方法も確かに良いのですが、使いたい時に xxxenv.bat を起動する手間は意外と大きかったりもするのです。またバッチファイルを作るのも手間でした。でも PATH 環境変数の長さにも限界があるし、毎回毎回 xxxenv.bat を作るのが面倒臭い。
分かります。そこで思いついたのが以下の新しい方法です。
マクロを使え
新しい方法といっても、基本は前の方法と変わりません。レジストリエディタを起動し、以下のキーに AutoRun という文字列値を作ります。
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Command Processor
文字列値の中身には以下を設定します。
%USERPROFILE%\init.cmd
Tumblr media
こうするとコマンドプロンプトが起動する度に %USERPROFILE%\init.cmd が実行されます。init.cmd の中身は簡単な内容です。
@echo off doskey /macrofile=%USERPROFILE%\init.macros if "%CMD_INIT_SCRIPT_LOADED%" neq "" goto :eof set CMD_INIT_SCRIPT_LOADED=1 set EDITOR=c:/dev/vim/vim.exe set GIT_EDITOR=c:/msys64/usr/bin/vim.exe set GRAPHVIZ_DOT=c:/dev/graphviz/bin/dot.exe set LANG=ja_JP.UTF-8 set GOROOT_BOOTSTRAP=c:\users\mattn\go1.13.5 set CMAKE_GENERATOR=MSYS Makefiles set GIT_SSH=c:\windows\system32\openssh\ssh.exe cls
冒頭で init.macros を doskey で読み込んでいる点を見て下さい。doskey コマンドにはエイリアス機能があるのですが、これを使って特定のコマンドをフルパスで参照しようというハックです。例えば僕の init.macros は以下の通り。
ls=ls --color=auto --show-control-chars -N $* licecap="C:\Program Files (x86)\LICEcap\licecap.exe" $* gimp="C:\Program Files\GIMP 2\bin\gimp-2.10.exe" $* vlc="C:\Program Files\VideoLAN\vlc\vlc.exe" $* code="C:\Users\mattn\AppData\Local\Programs\Microsoft VS Code\bin\code.cmd" $* ag=ag --nocolor $* ssh=c:\msys64\usr\bin\ssh.exe $* find=c:\msys64\usr\bin\find.exe $* vi=vim $* mv=mv -i $* cp=cp -i $* rm=rm -i $* grep=grep --color=auto $* java="c:\Program Files\Java\jdk-13\bin\java" $* julia=c:\users\mattn\AppData\Local\Julia-1.3.1\bin\julia $* conda=c:\users\mattn\Miniconda3\Library\bin\conda.bat $* vcvars64="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" choco=C:\ProgramData\chocolatey\bin\choco.exe $* vagrant=c:\dev\vagrant\bin\vagrant.exe $* docker="C:\Program Files\Docker\Docker\resources\bin\docker.exe" $* docker-compose="C:\Program Files\Docker\Docker\resources\bin\docker-compose.exe" $* tinygo=c:\dev\tools\tinygo\bin\tinygo.exe $*
短い名前をフルパスで登録する事で PATH 環境変数を弄る事無く、コマンドを直接実行できる様になるという訳です。
これらのコマンドそれぞれに PATH を通すのは面倒ですし、xxxenv.bat を作るのは面倒ですよね。この面倒さから開放されたのです。メンテするのは init.macros だけなのですから、随分と楽になりました。
注意点
この方法が使えるのは、あくまでインタラクティブシェルの中だけです。コマンドプロンプトから docker コマンドは使える様になりましたが、そのコマンドプロンプトから起動するバッチファイルの中で docker を実行してもパスが通っていないのでエラーになります。ただ、それはそのバッチファイルがちゃんとフルパスで起動するか、バッチファイルの中で PATH を通しさえすれば解決する話です。
実はこの方法は既に 2017 年の時点で思いついていて、ずっとこの環境で実践してきましたが特に問題は起きていません。
ちなみに僕が直した方法ですが、PATH には追加しない(もしくは一番後ろ)ようにして、レジストリで読ませる init.cmd に doskey git=c:\msys64\usr\bin\git.exe $* を書きました。
— mattn (@mattn_jp) September 13, 2017
Windows のコマンドプロンプトで生きておられる方にオススメしたいハックです。
from Big Sky https://ift.tt/2ZJ9XYY
3 notes · View notes
mattn · 5 years ago
Text
画像に再生マークつけるだけのコマンド作った。
元ネタ
画像に再生マークつけるだけのツール作った。 https://t.co/13epnr450j pic.twitter.com/NCZujPxEZ7
— ryomatsu (@ryomatsu) June 18, 2020
作ったもの。
mattn/fakemovie · GitHub https://ift.tt/2Yd0eZW
Go のパッケージにしてあるので、Go の HTTP サーバからサーブする画像全てに再生ボタンを付ける様なミドルウェアを作る事もできてとても便利です。一応、オマケとしてコマンドを用意してあります。
$ fakemovie -r 40 input.png
Tumblr media
こんな感じに使えるのでご利用下さい。
from Big Sky https://ift.tt/2CmhKTc
0 notes
mattn · 5 years ago
Text
画像に再生マークつけるだけのコマンド作った。
元ネタ
画像に再生マークつけるだけのツール作った。 https://t.co/13epnr450j pic.twitter.com/NCZujPxEZ7
— ryomatsu (@ryomatsu) June 18, 2020
作ったもの。
mattn/fakemovie · GitHub https://ift.tt/2Yd0eZW
Go のパッケージにしてあるので、Go の HTTP サーバからサーブする画像全てに再生ボタンを付ける様なミドルウェアを作る事もできてとても便利です。一応、オマケとしてコマンドを用意してあります。
$ fakemovie -r 40 input.png
Tumblr media
こんな感じに使えるのでご利用下さい。
from Big Sky https://ift.tt/3eeX2Tn
0 notes
mattn · 5 years ago
Text
画像に再生マークつけるだけのコマンド作った。
元ネタ
画像に再生マークつけるだけのツール作った。 https://t.co/13epnr450j pic.twitter.com/NCZujPxEZ7
— ryomatsu (@ryomatsu) June 18, 2020
作ったもの。
mattn/fakemovie · GitHub https://ift.tt/2Yd0eZW
Go のパッケージにしてあるので、Go の HTTP サーバからサーブする画像全てに再生ボタンを付ける様なミドルウェアを作る事もできてとても便利です。一応、オマケとしてコマンドを用意してあります。
$ fakemovie -r 40 input.png
Tumblr media
こんな感じに使えるのでご利用下さい。
from Big Sky https://ift.tt/3egeAhS
0 notes
mattn · 5 years ago
Text
C++ で flask ライクなウェブサーバ「clask」書いた。
今まで C++ でちょっとしたウェブアプリを作る際は crow という micro-framework を使ってきました。
GitHub - ipkn/crow: Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)
How to Build If you just want to use crow, copy amalgamate/crow_all.h and include it. Requirements C...
https://ift.tt/TrRD1t
ヘッダオンリーで使えてとても便利だったのですが、boost に依存している点があまり好きじゃなかったのと、最近 crow の開発が止まり最新の boost でビルド出来なくなってしまったので、自分で作る事にしました。
GitHub - mattn/clask: Web micro-framework like flask in C++.
# include " clask/core.hpp " int main () { auto s = clask::server (); s. GET ( " / " , [](clask::req...
https://ift.tt/2BCursv
C++ から flask ぽく使える事を目指しました。ヘッダオンリーで使えます。HTTP ヘッダを解析する所だけ kazuho さんの picohttpparser を使わせて頂いています。
#include "clask/core.hpp" int main() {   auto s = clask::server();   s.GET("/", [](clask::request& req) {     return "OK!";   });   s.GET("/foo", [](clask::response& resp, clask::request& req) {     resp.set_header("content-type", "text/html");     resp.write("he<b>l</b>lo");   });   s.run(); }
boost にも依存していませんし Windows でも問題なく動作します。ただしコンパイルには C++17 をサポートしているコンパイラが必要です。keep-alive に対応したマルチスレッドなウェブサーバなので、静的な2文字("OK)くらいのコンテンツだと 70000req/sec くらい出ます(ログ出力を無効にした場合/Ryzen 5)。まだまだ実験的ですが、幾らかアプリケーションが作れるまで来たので、今後簡単な C++ のウェブアプリは clask を使って行こうと思っています。ドキュメントが皆無なのですが、これから整備していく予定です。使用例を5つほど用意していますので、興味のある方は pull-request 頂けると嬉しいです。
clask/example at master · mattn/clask · GitHub
Explore GitHub → Learn & contribute Topics Collections Trending Learning Lab Open source guides...
https://ift.tt/37Djbbp
from Big Sky https://ift.tt/30RQhmq
0 notes
mattn · 5 years ago
Text
WSL2 でクリップボード使いたい。
WSL2 がリリースされ Windows 10 Home Edition でも使える様になったので色々遊んでるのだけど、Windows 側とテキストを交換したい時に面倒で、クリップボードを共有する方法を模索した。
最悪 /dev/clipboard を実装するまで考えたけど、面倒過ぎたし exe の実行厳しい(何か常駐させてユーザランドから起動する為にサーバがいる)だろうから別の方法を考えた。WSL2 は binfmt (たぶん違うけど良く似た奴だろう) で Windows の exe が起動できるので、コマンド経由で stdin/stdout を read/write できる物を起動する方法を考えた。
で自分で書くかと Windows Terminal 起動した時点で「Windows Terminal からコピペできるやん、いらなくね?」となり、本来の目的を忘れかけていたので、おとなしく GitHub からそういったコマンドを探した。
GitHub - equalsraf/win32yank: Windows clipboard tool
Dismiss Join GitHub today GitHub is home to over 50 million developers working together to host and ...
https://ift.tt/2sABUDu
こちら便利そうだったけど、僕は Go 言語使いなので、go get で一発で入るのが欲しかった。最終的には以下のリポジトリにある gocopy と gopaste が良さそうだった。
GitHub - atotto/clipboard: clipboard for golang
Clipboard for Go Provide copying and pasting to the Clipboard for Go. Build: -1 go get github.com/ato...
https://ift.tt/1A1iEI7
Windows 側では以下の様にインストールする。
go get github.com/atotto/clipboard/cmd/gocopy go get github.com/atotto/clipboard/cmd/gopate
あとは WSL2 の .bash_aliases に以下を足した。
alias gocopy=/mnt/c/Users/mattn/go/bin/gocopy.exe alias gopaste=/mnt/c/Users/mattn/go/bin/gopaste.exe
パスは個人によって違うの修正して下さい。
$ echo あいう | gocopy $ gopaste あいう
こんな感じに使う。
追記
Vim から :w !goclip したいのであれば alias じゃなく shell で wrapper 書くかシンボリックリンクを WSL2 のパスの通った所に張るのが良さそうです。ちなみに PowerShell の get-clipboard と clip.exe でも出来るけど遅いのが嫌いなのでこの方法にしました。
from Big Sky https://ift.tt/36RgTVO
2 notes · View notes
mattn · 5 years ago
Text
書評「プログラミング言語大全」
技術評論社様より献本頂きました。
Tumblr media
プログラミング言語大全 クジラ飛行机 技術評論社 単行本(ソフトカバー) / ¥1,980 (2020年04月18日)   発送可能時間:
色々なプログラミング言語の生い立ちや特色、エピソード、それらの言語での FizzBuzz の書き方など、プログラミングを始めたばかりの方が読んで楽しめる本だと思います。
僕も昔からプログラミング言語が大好きなので色々なプログラミング言語を触ってきましたし、自作言語もいくらか作ってきました。僕の初めてのプログラミング言語は BASIC でした。シャープの MZ シリーズの高速化が行われ「スーパー MZ」と呼ばれていた MZ-2500 を使い、自作のゲームを作っていました。あの頃のマイコンや BASIC は今と比べるととてもチープで、出来る事も限られていました。しかしそのお陰で僕達パソコン少年達は Z80 という CPU を高速に扱う為にハンドアセンブル(アセンブラが高価すぎて買えないので変換表を見ながらニーモニックを打ち込む事)を覚える事ができました。今から考えると、あれだけコンピュータに真正面から向き合って多くの時間を費やしてプログラミングに打ち込めたのはとても貴重な時間だったなと思います。
あの頃のパソコン少年たちは今どうしてるんでしょうね。僕がプログラミング言語を触り始めた時には、プログラミング言語を選ぶ事なんか出来ませんでした。当たり前の様に BASIC を使い、高速化の為にアセンブリを覚えました。しかし今は違います。自分の好きなスタイルの、目的に近い、そして速く簡単に書けるプログラミング言語を探す事ができる様になりました。とても恵まれた話です。インタプリタ言語だけでなく、静的型付け言語もあります。Ruby に対する JRuby の様に異なる処理系が幾つも存在する事もあります。TypeScript の様に実際に動作する JavaScript 上に作られた別のプログラミング言語もあります。もう10年するとさらに多くのプログラミング言語が登場しているかもしれませんね。今回読んだ本書で登場してくるプログラミング言語のおよそ 6~7 割を触った事がありましたが、もう 10 年後に登場しているであろうプログラミング言語の多くはもう把握できていないかもしれませんね。
僕は Erlang や Elixir は触った事はあるものの、どの様な経緯で作られた言語なのか、また最近だとどの企業で採用されているかなど、まったく知らなかったのですが本書で知る事ができてとても興味深く読ませて頂きました。知らない事も沢山書かれています。初級中級の方だけでなく上級の方でも十分に楽しめる本だと思いました。
from Big Sky https://ift.tt/3ahz5YD
6 notes · View notes
mattn · 5 years ago
Text
C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
僕はよく C++ 用の SQLite3 ライブラリを探し歩いていて、見つけるたびに「1行掲示板」を実装してみている。
ウェブサーバは crow というライブラリを使い、SQLite3 の部分だけ差し替えて試すという感じ。初代は MySQL 用に作った。
GitHub - mattn/crow-bbs https://ift.tt/2XxpnP5
これを SQLite3 向けに直したのが crow-bbs-sqlite3
GitHub - mattn/crow-bbs-sqlite3 https://ift.tt/2V1xyl5
さらにそれを sqlpp11 向けに直したのが crow-bbs-sqlite3-sqlpp11
GitHub - mattn/crow-bbs-sqlite3-sqlpp11 https://ift.tt/2t1FsK8
sqlpp11 は SQLite3 専用という訳ではなく、connector を使って異なる RDBMS も扱える。
先日、C++ 用 SQLite3 ORM の sqlite_orm を見つけたのでこれも試してみた。
GitHub - fnc12/sqlite_orm: ❤️ SQLite ORM light header only library for modern C++
// SELECT AVG(id) FROM users auto averageId = storage.avg(&User::id); cout << " averageId = " << ave...
https://ift.tt/2hVSbbv
作った物はこちら。
GitHub - mattn/crow-bbs-sqlite3-sqlite_orm https://ift.tt/34FiahH
sqlite_orm は SQLite3 専用ではあるものの、sqlite3 ネイティブライブラリの様に SQLite3 色が濃くなく、sqlpp11 の様に SQL も登場しない。初回のスキーマ構築で struct との bind を行う。
struct Post {   int id;   std::string text;   std::string created; };
auto storage = sqlite_orm::make_storage("bbs.db",     sqlite_orm::make_table("bbs",       sqlite_orm::make_column("id", &Post::id, sqlite_orm::autoincrement(), sqlite_orm::primary_key()),       sqlite_orm::make_column("text", &Post::text),       sqlite_orm::make_column("created", &Post::created) )); storage.sync_schema();
全ての Post を得るのであれば1行で出来る。
auto posts = storage.get_all<Post>();
追加も簡単
Post post = {.text = q, .created = storage.select(sqlite_orm::datetime("now", "localtime")).front()}; storage.insert(post);
1行掲示板くらいのアプリであればとても小さく書ける。
#include <memory> #include <stdexcept> #include "crow_all.h" #include <sqlite_orm/sqlite_orm.h> struct Post {   int id;   std::string text;   std::string created; }; int main() {   auto storage = sqlite_orm::make_storage("bbs.db",       sqlite_orm::make_table("bbs",         sqlite_orm::make_column("id", &Post::id, sqlite_orm::autoincrement(), sqlite_orm::primary_key()),         sqlite_orm::make_column("text", &Post::text),         sqlite_orm::make_column("created", &Post::created)   ));   storage.sync_schema();   crow::SimpleApp app;   crow::mustache::set_base(".");   CROW_ROUTE(app, "/")   ([&] {     crow::mustache::context ctx;     auto posts = storage.get_all<Post>();     int n = 0;     for(auto &post : posts) {       ctx["posts"][n]["id"] = post.id;       ctx["posts"][n]["text"] = post.text;       ctx["posts"][n]["created"] = post.created;       n++;     }     return crow::mustache::load("bbs.html").render(ctx);   });   CROW_ROUTE(app, "/post").methods("POST"_method)   ([&](const crow::request& req, crow::response& res) {     crow::query_string params(std::string("?") + req.body);     char* q = params.get("text");     if (q == nullptr) {       res = crow::response(400);       res.write("bad request");       res.end();       return;     }     Post post = {.text = q, .created = storage.select(sqlite_orm::datetime("now", "localtime")).front()};     storage.insert(post);     res = crow::response(302);     res.set_header("Location", "/");     res.end();   });   app.port(40081)     //.multithreaded()     .run(); }
ちょっと触ってみた感じだと SQLite3 を扱うのであれば一番便利かもしれない。
from Big Sky https://ift.tt/2VknouW
0 notes
mattn · 5 years ago
Text
Go言語で Lisp 処理系を作った。
1週間ほど前の深夜、ふと Go で連結リスト構造を書いていたら次第に car/cdr 形式になってしまい、気付いたら手が滑って Lisp 処理系を作り始めてしまいました。
なぜかこんな時間から突然 lisp を書き始めてしまった。
— mattn (@mattn_jp) March 26, 2020
初日は深夜だったのでパーサを書いた所で終了。次の日の夕方には四則演算と FizzBuzz が動きました。実は Lisp 処理系を書くのは人生でたぶん4回目くらいで、前回はC言語で書きました。
GitHub - mattn/cisp: Minimal Lisp Interpreter https://ift.tt/296oKoT
今回のルールとして「過去の自分の実装や他の実装は見ない」というオレオレルールを作ってしまったので幾分時間が掛かってしまった様に思います。テストコードはさすがにいいだろという事で、cisp のテストコードは借りました。マクロを除いて cisp と互換性があります。
今回 Lisp 処理系を書きながらなんとなくやってみたいなと思っていたのが Lisp での非同期処理。Go言語の goroutine と channel を使って通信出来たらどんな物ができるだろう、という研究目的でした。
本日ようやく goroutine/channel が動いたのでブログで公開しておきます。
GitHub - mattn/golisp: Lisp Interpreter https://ift.tt/2wxkVoE
(go:make-chan string) で chan を作る事ができ、(go:chan-send ch "foo") で送信、(go:chan-recv ch) で受信する事ができます。また (go (print 1) (print 2)) で goroutine が起動するので、以下の様な channel を使った通信ができます。
(setq time (go:import time)) (let ((ch (go:make-chan string 1)))     (go         (.Sleep time 1e9)         (go:chan-send ch "1")         (.Sleep time 1e9)         (go:chan-send ch "2")         (.Sleep time 1e9)         (go:chan-send ch "3")         (.Sleep time 1e9)         (go:chan-send ch "ダーッ!")     )     (print (car (go:chan-recv ch)))     (print (car (go:chan-recv ch)))     (print (car (go:chan-recv ch)))     (print (car (go:chan-recv ch))) )
研究の成果としては、面白い動きが確認できたのでまずまずの成果と思います。上記の様に Go のパッケージを import して関数やメソッドを呼び出せる様になっています。例えば乱数を表示するには以下の様に実行します。
(setq time (go:import 'time)) (setq rand (go:import 'math/rand)) (.Seed rand (.UnixNano (.Now time))) (print (.Int rand))
今の所、実用的ではありませんが、細々とメンテナンスしていってツールを書く程度に使えるまでは持っていきたいと思います。
from Big Sky https://ift.tt/2wfvfBj
0 notes
mattn · 5 years ago
Text
Go 言語のスライス挿入ベンチマーク
Go でスライスに挿入する例として Go の Wiki に以下の物が記載されている。
作ろうしているツールで、 Goのスライスのinsertをする必要があって、 スライスの動きを理解するために、自分で実装したあとに、Goの公式Wikiを見て���いいなと思ったhttps://t.co/vmonuxbjOl a = append(a[:i], append([]T{x}, a[i:]...)...)
— ゴリラ@バナナバナナバナナバナナバナナバナナバナナバナナバナナバナナバナナバナナバナナバナナバナナ (@gorilla0513) April 4, 2020
しかしこのコードは、挿入されるスライスから部分スライスを取り出し、そこに挿入するスライスを append に割り当てる為に展開し、さらに残りの部分スライスも append に割り当てる展開を行っている。なので実装コードとしては短いが、実際に実行されるオペレーションコードが冗長になる。また、スライスの伸長はおよそ2倍ずつ増える。なので例えば 5000 個のスライスに 1000 個のアイテムを挿入すると、キャパシティはおよそ 12000 近くになる。Go ではこういったスライスの操作も、基本的には自身で make によりメモリを確保し、ループで値を割り当てるのが良い(面倒かもしれないがその方がメモリも節約され速い)とされている。
以下、ベンチマークを取ってみる。
package main_test import (     "reflect"     "testing" ) type T int func BenchmarkAppend(b *testing.B) {     b.ResetTimer()     input := make([]int, 5000)     for i := 0; i < 5000; i++ {         input[i] = i     }     insert := make([]int, 1000)     for i := 0; i < 1000; i++ {         insert[i] = i     }     expected := make([]int, 6000)     for i := 0; i < 6000; i++ {         if i < 1000 {             expected[i] = i         } else if i < 2000 {             expected[i] = i - 1000         } else {             expected[i] = i - 1000         }     }     n := 1000     var output []int     b.ResetTimer()     for i := 0; i < b.N; i++ {         output = append(input[:n], append(insert, input[n:]...)...)     }     b.StopTimer()     if !reflect.DeepEqual(output, expected) {         b.Fatal("bad insertion")     } } func BenchmarkNormal(b *testing.B) {     input := make([]int, 5000)     for i := 0; i < 5000; i++ {         input[i] = i     }     insert := make([]int, 1000)     for i := 0; i < 1000; i++ {         insert[i] = i     }     expected := make([]int, 6000)     for i := 0; i < 6000; i++ {         if i < 1000 {             expected[i] = i         } else if i < 2000 {             expected[i] = i - 1000         } else {             expected[i] = i - 1000         }     }     n := 1000     var output []int     b.ResetTimer()     for i := 0; i < b.N; i++ {         output = make([]int, len(input)+len(insert))         for l := 0; l < n; l++ {             output[l] = input[l]         }         for l := 0; l < len(insert); l++ {             output[l+n] = insert[l]         }         for l := n; l < len(input); l++ {             output[l+len(insert)] = input[l]         }     }     b.StopTimer()     if !reflect.DeepEqual(output, expected) {         b.Fatal("bad insertion")     } } func BenchmarkCopy(b *testing.B) {     input := make([]int, 5000)     for i := 0; i < 5000; i++ {         input[i] = i     }     insert := make([]int, 1000)     for i := 0; i < 1000; i++ {         insert[i] = i     }     expected := make([]int, 6000)     for i := 0; i < 6000; i++ {         if i < 1000 {             expected[i] = i         } else if i < 2000 {             expected[i] = i - 1000         } else {             expected[i] = i - 1000         }     }     n := 1000     var output []int     b.ResetTimer()     for i := 0; i < b.N; i++ {         output = make([]int, len(input)+len(insert))         copy(output, input[:n])         copy(output[n:], insert)         copy(output[n+len(insert):], input[n:])     }     b.StopTimer()     if !reflect.DeepEqual(output, expected) {         b.Fatal("bad insertion")     } }
BenchmarkAppend-8          42700             26185 ns/op BenchmarkNormal-8          70170             18005 ns/op BenchmarkCopy-8            90902             15787 ns/op
Wiki に載っているコードは、手動でスライスを挿入するコードの1.5~2倍遅い。copy を使うともう少し速い。
Tumblr media
みんなのGo言語[現場で使える実践テクニック] 松木雅幸, mattn, 藤原俊一郎, 中島大一, 牧大輔, 鈴木健太 技術評論社 Kindle版 / ¥2,178 (2016年09月09日)   発送可能時間:今すぐダウンロードできます。
from Big Sky https://ift.tt/2V0oNGL
0 notes
mattn · 5 years ago
Text
Go 言語で変数のシャドウイングを避けたいなら shadow を使おう。
var hoge *Hoge if condition != nil { hoge, err := https://t.co/3dOQ15DCmc(ctx, hoge_key) if err != nil { return nil, err } fmt.Printf("%v", *hoge) } else { hoge = nil } こんな感じのコードで死んでたんですが、うっかりhogeがnil担っちゃうの防ぐにはどうしたら・・・(文字数
— chidakiyo (@chidakiyo) February 26, 2020
こういった場合に便利なのがオフィシャルが提供している解析コマンド shadow です。(相変わらずググらび...)
インストールは以下を実行します。
$ go get golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
ツイートされておられる以下のコードで実行してみます。
package main import (     "fmt" ) var condition = true func main() {     var hoge *string     if condition {         hoge, err := do("word")         if err != nil {             return         }         fmt.Printf("checkpoint: %v\n", *hoge)     } else {         hoge = nil     }     fmt.Printf("RESUT: %v\n", hoge) } func do(v string) (*string, error) {     return &v, nil }
.../main.go:13:3: declaration of "hoge" shadows declaration at line 11
便利。
Tumblr media
改訂2版 みんなのGo言語 松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太 技術評論社 / (2019-08-01)   発送可能時間:
from Big Sky https://ift.tt/3cf6jdh
1 note · View note
mattn · 5 years ago
Text
書評: Visual Studio Code 実践ガイド
執筆者様に Twitter でお声掛け頂き、発売前ながら献本頂く事になりました。執筆された森下様、送付頂いた技術評論社様、ありがとうございました。
Tumblr media
Visual Studio Code実践ガイド —— 最新コードエディタを使い倒すテクニック 森下 篤 技術評論社 / (2020-02-21)   発送可能時間:
Visual Studio Code は登場から色々な機能を取り込みつつ着実にユーザを増やし、統合開発環境としては今や飛ぶ鳥を落とす勢いになった言って良いでしょう。以下は 2019 年の Stackoverflow Survey で公開された有名な開発環境の調査結果です。
Tumblr media
僕は普段は Vim というテキストエディタを使っていますが、実は僕は色々なテキストエディタを試します。Emacs も人並み程度使えますし、Visual Studio Code も拡張を自分で書いた事がある程度には使っています。
Search results - mattn | Visual Studio Code , Visual Studio Marketplace
...
https://ift.tt/39ZWmyr
正直に言うと、Visual Studio Code が登場後しばらく経ってから端末表示機能を実装した時に、少しだけ悔しくて同時期に Vim の作者 Bram Moolenaar 氏が「端末機能を足そう」と言い出した時には誰よりも早く、そして Bram Moolenaar 氏による UNIX の実装よりも早く Windows のパッチを送った事を覚えています。そして個人的には今も尚、Visual Studio Code は良い目標の1つだと思っています。
本書は Visual Studio Code を知らない開発者が Visual Studio Code を使いこなせる様になるまでに、机の片隅に置いておくと便利な一冊となるでしょう。各ツールバーやコマンドパレット、Visual Studio Code での Git の扱い方、デバッガの使い方、拡張のインストールや拡張の作り方、Visual Studio Code を使った TypeScript 開発の実例を交えた説明、Go 開発の実例を交えた説明、多くの方がマッチしそうな内容になっています。本書を片手に写経しながら読み進めたならば、おそらく Visual Studio Code をあまり触った事が無かった方でも読み終わる頃には使いこなせる様になっているのではないかと思います。
筆者は Visual Studio Code が登場した当初から Visual Studio Code を使っていますが、それでも知らない内容が沢山書かれていました。Visual Studio Code には自分が扱う言語拡張しかインストールしていなかったので、Visual Studio Code が扱えるデバッガ多さを紹介した画面キャプチャには驚きました。またデバッガの設定情報が書かれている launch.json で console や useWSL といった項目があり、それらを使ってもっと便利にデバッグできる事も知りました。とても勉強になりました。
一番の収穫は、特定のワークスペースでのみ拡張を有効にする為の設定でした。この辺りを知りたい方は、ぜひ購読してみるのが良いと思います。
本書で1点、惜しいなと思う事をあえて言うとすれば索引が若干少ない所だと思います。400ページを超えるこれだけのボリュームで内容も程よく濃いので、後から読み返したくなる事は間違いなくあると思います。そんな時に索引から読みたい箇所に戻れるととても便利だろうなと思いました。個人的に特に良かったなと思ったのが Visual Studio Code を使っての todo アプリ開発を TypeScript と Go の両方で実践している章でした。これらはこれから実務で統一的に Visual Studio Code を使って行こうとされておられる企業の方々には良い教科書になりえると思いました。
ところで最近、Vim の Language Server 事情も少し変化があり、筆者が vim-lsp-settings という、Language Server Client である vim-lsp のサポートを行うプラグインを作っています。多くの Language Server を Visual Studio Code 並みに簡単にインストールする事ができる様になっています(coc よりも多いです)。直近では Visual Studio Code の様にプロジェクト専用設定を行う事もできる様になったので、ワークスペース専用にデータベース接続先を設定する事も可能です。lighttiger2505 さんが開発しておられる SQL の Language Server、sqls も簡単にインストールする事ができます。さらに efm-langserver という汎用の Language Server との連携も便利です。tsuyoshicho さんが作ってくれている vim-efm-langserver-settings を入れるとインストールされているツール類を linter として多くのフォーマットのエラーをチェックする事が出来る様になっています。こういった Language Server に関するアイデアはエディタの垣根を越えて共有される、とてもフェアな良い技術の進歩であり僕もやっていて楽しいです。これからも Visual Studio Code に追いつける様に頑張っていきたいと思います。
今後も、Visual Studio Code と気持ちよい技術的な競争ができるといいなと本書を読んで改めて思いました。
from Big Sky https://ift.tt/32lxkaB
0 notes
mattn · 5 years ago
Text
Go 言語の struct の実体を引数で(なるべく)渡せない様にするテクニック
Go 言語は struct のレシーバがポインタの場合は実体であってもポインタの場合であっても呼び出せるので、もし struct が参照カウントに従い動作する様な場合は実体でコピーされてしまっては困る場合があります。例えば以下の様なインタフェースを考えます。
package main import (     "fmt"     "sync/atomic"     "time" ) type foo struct {     n int64     q chan struct{} } func (f *foo) Add() {     if atomic.AddInt64(&f.n, 1) == 1 {         f.q = make(chan struct{})     } } func (f *foo) Done() {     if atomic.AddInt64(&f.n, -1) == 0 {         f.q <- struct{}{}     } } func (f *foo) Watch() {     <-f.q } func main() {     var f foo     f.Add()     f.Add()     f.Add()     go func() {         fmt.Println("いーち!")         time.Sleep(time.Second)         f.Done()         fmt.Println("にー!")         time.Sleep(time.Second)         f.Done()         fmt.Println("さーん!")         time.Sleep(time.Second)         f.Done()     }()     f.Watch()     fmt.Println("ダーッ!") }
このコードは main の中だけで動く場合には機嫌良く動きます。次にこの処理を分散してみたい考えてみます。関数 doSomething1 と doSomething2 に foo を引数で渡します。
func doSomething1(f foo) {     time.Sleep(2 * time.Second)     fmt.Println("さーん!")     time.Sleep(time.Second)     f.Done() } func doSomething2(f foo) {     fmt.Println("いーち!")     time.Sleep(time.Second)     f.Done()     fmt.Println("にー!")     time.Sleep(time.Second)     f.Done() } func main() {     var f foo     f.Add()     f.Add()     f.Add()     go doSomething1(f)     go doSomething2(f)     f.Watch()     fmt.Println("ダーッ!") }
この処理は一見うまく行きそうに見えます。しかし実行するとデッドロックが起きます。
いーち! にー! さーん! fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan receive]: main.(*foo).Watch(...)     C:/Users/mattn/go/src/github.com/mattn/misc/inoki_app/main.go:27 main.main()     C:/Users/mattn/go/src/github.com/mattn/misc/inoki_app/main.go:55 +0xfd
「しっかり atomic.AddInt64 を使っているのにおかしい」と思うかもしれません。しかし実際は doSomething1 や doSomething2 の引数として foo の実体を渡した際にはコピーが発生してしまいます。参照カウンタである foo.n は両方の関数に 2 が渡り、foo.n が 0 になる事はありません。もちろんこれは引数をポインタにする事で回避できます。
func doSomething1(f *foo) {     time.Sleep(2 * time.Second)     fmt.Println("さーん!")     time.Sleep(time.Second)     f.Done() } func doSomething2(f *foo) {     fmt.Println("いーち!")     time.Sleep(time.Second)     f.Done()     fmt.Println("にー!")     time.Sleep(time.Second)     f.Done() } func main() {     var f foo     f.Add()     f.Add()     f.Add()     go doSomething1(&f)     go doSomething2(&f)     f.Watch()     fmt.Println("ダーッ!") }
こういった struct をライブラリとして提供したい場合、使い手側に「ポインタで使って欲しい」と示す事ができないと、いくらでもバグが発生してしまいます。そこで使うテクニックが noCopy です。Go 言語を知っていてここまで読んだ方であれば、これが何かに似ていると気付いたはずです。そう sync.WaitGroup です。sync.WaitGroup も実体で引数に渡すとデッドロックが発生します。sync.WaitGroup の場合は以下のテクニックを使っています。
type WaitGroup struct {     noCopy noCopy     // 64-bit value: high 32 bits are counter, low 32 bits are waiter count.     // 64-bit atomic operations require 64-bit alignment, but 32-bit     // compilers do not ensure it. So we allocate 12 bytes and then use     // the aligned 8 bytes in them as state, and the other 4 as storage     // for the sema.     state1 [3]uint32 } type noCopy struct{} func (*noCopy) Lock()   {} func (*noCopy) Unlock() {}
go vet は Go 言語でのお作法の良くない書き方を検出してくれるツールですが、この Lock() と Unlock() を持ったインタフェースを実体でコピーしようとすると go vet の copylocks というチェック機能により警告がでる仕組みになっています。
# github.com/mattn/misc/inoki_app .\main.go:5:21: doSomething passes lock by value: sync.WaitGroup contains sync.noCopy .\main.go:11:14: call of doSomething copies lock value: sync.WaitGroup contains sync.noCopy
実際に組み込んでみましょう。
package inoki import (     "sync/atomic" ) type noCopy struct{} func (*noCopy) Lock()   {} func (*noCopy) Unlock() {} type Toukon struct {     noCopy noCopy     n int64     q chan struct{} } func (f *Toukon) Add() {     if atomic.AddInt64(&f.n, 1) == 1 {         f.q = make(chan struct{})     } } func (f *Toukon) Done() {     if atomic.AddInt64(&f.n, -1) == 0 {         f.q <- struct{}{}     } } func (f *Toukon) Watch() {     <-f.q }
言語仕様上、禁止する事はできないのでコンパイルは出来てしまいますが、go vet を使う IDE 等ではちゃんと警告がでる様になっています。
Tumblr media
便利なテクニックなので使ってみてみるといいと思います。
Tumblr media
改訂2版 みんなのGo言語 松木 雅幸, mattn, 藤原 俊一郎, 中島 大一, 上田 拓也, 牧 大輔, 鈴木 健太 技術評論社 / (2019-08-01)   発送可能時間:
from Big Sky https://ift.tt/37IjRuj
1 note · View note
mattn · 5 years ago
Text
zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。
vim-jp の Slack で「zsh の PATH 環境変数に相対パスを含んでいる場合、補完ができないけど意図的か」という話題が出たので調べてみた。
補完できない様にしているのはこの変更
39104: do not hash relative paths in findcmd() · zsh-users/zsh@b312abc https://ift.tt/39pnruy
結構古い変更。この変更が行われた理由を追ってみた所、メーリングリストでこの会話が見つかった。
Running 'type' causes false positive hashed command completion
Zsh Mailing List Archive Messages sorted by: Reverse Date , Date , Thread , Author Running 'type' ca...
https://ift.tt/2OH0hrQ
$ zsh -f % cd $(mtemp -d) % touch sudofoo; chmod +x $_ % ./sudo<TAB> <becomes> % ./sudofoo <^C> % type -w ./sudo ./sudo: none % ./sudo<TAB> ./sudo    sudofoo* That's wrong because ./sudo does not exist.  However, it's hashed: % print $commands[./sudo] /usr/bin/./sudo To confuse matters further, even though "./sudo" is hashed, a subsequent 'type -w ./sudo' will print "none", because the hash node lacks the HASHED bit in its .flags and the PATH_DIRS option is unset by default.
「/usr/bin 対しては ./sudo が存在する為、sudofoo に対する ./sudo からの補完候補に sudo が出てきてしまう、これは混乱を生んでしまう」という物だった。これを回避する為に上記の変更で相対パスはハッシュしない様にしている。ちなみに bash や fish だと相対パスの中のコマンドも補完された。
相対パス上で sudofoo の一部 sudo が補完されてしまったとして困るのは、その相対パス内に危ないファイルを追加してしまった場合だろうと推測するが、そもそも相対パスを PATH に追加したい要件が僕には見つからなかった。おそらく自動的に node_modules/.bin 内のコマンドを扱える様にしたいといった物だと思う。もし zsh でやりたい人は direnv を使って動的に PATH を追加するのが良いと思う。
from Big Sky https://ift.tt/31Hwa99
5 notes · View notes
mattn · 5 years ago
Text
Oracle Cloud Function でしりとりした。
昨年から Oracle Cloud の無料枠を使っています。2 vCPU な VM を2台も無料で使わせて頂けるという Oracle Cloud さんの大盤振る舞いに感謝しつつ、Oracle Cloud Function でしりとりをしてみました。
Oracle Cloud Function は Fn Project というサーバレスプラットフォームをベースにしており、同プロジェクトの fn というツールを使う事で、他の Fn Project を使うクラウドと同様に操作を行う事ができ���す。
Fn Project
Open Source. Container-native. Serverless platform.
https://fnproject.io/
fn コマンドは以下の手順でインストールする事ができます。
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh
MacOS の場合は homebrew からインストールが可能。
brew update && brew install fn
Windows の場合は僕が送っている pull-request を使わないとエラーになります。ソースを git clone して go build して下さい。
Fix atomicwrite for Windows by mattn - Pull Request #605 - fnproject/cli https://ift.tt/2NFTVZ6
fn コマンドを使える様になるまでは sugimount さんが Qiita に書いている記事を参考にしました。
サーバレスな Oracle Functions (Fn) をやってみた - Qiita https://ift.tt/36d2iSq
注意点としては、Oracle Cloud はデフォルトで VCN が作られていますが、Function を使う場合は別途 VCN を作らないと DHCP オプションが一致しないというエラーが出てしまいます。新しく作って下さい。あと sugimount さんが書かれているリポジトリ名と異なる物が実際には用意されるので、詳細は Oracle Cloud のダッシュボードからファンクションを選択し、アプリケーション詳細の「開始」タブを見るとほぼやるべき事が書いてあります。
Tumblr media
アプリケーションを作る所まで出来たら、しりとりサーバを作ります。短いのでコード全体を載せます。
package main import (     "bufio"     "context"     "encoding/json"     "errors"     "io"     "math/rand"     "strings"     _ "func/statik"     fdk "github.com/fnproject/fdk-go"     "github.com/rakyll/statik/fs" ) var upper = strings.NewReplacer(     "ぁ", "あ",     "ぃ", "い",     "ぅ", "う",     "ぇ", "え",     "ぉ", "お",     "ゃ", "や",     "ゅ", "ゆ",     "ょ", "よ", ) func kana2hira(s string) string {     return strings.Map(func(r rune) rune {         if 0x30A1 <= r && r <= 0x30F6 {             return r - 0x0060         }         return r     }, s) } func hira2kana(s string) string {     return strings.Map(func(r rune) rune {         if 0x3041 <= r && r <= 0x3096 {             return r + 0x0060         }         return r     }, s) } func search(text string) (string, error) {     rs := []rune(text)     r := rs[len(rs)-1]     statikFS, err := fs.New()     if err != nil {         return "", err     }     f, err := statikFS.Open("/dict.txt")     if err != nil {         return "", err     }     defer f.Close()     buf := bufio.NewReader(f)     words := []string{}     for {         b, _, err := buf.ReadLine()         if err != nil {             break         }         line := string(b)         if ([]rune(line))[0] == r {             words = append(words, line)         }     }     if len(words) == 0 {         return "", errors.New("empty dictionary")     }     return words[rand.Int()%len(words)], nil } func shiritori(text string) (string, error) {     text = strings.Replace(text, "ー", "", -1)     if rand.Int()%2 == 0 {         text = hira2kana(text)     } else {         text = kana2hira(text)     }     return search(text) } func handleText(text string) (string, error) {     rs := []rune(strings.TrimSpace(text))     if len(rs) == 0 {         return "", errors.New("なんやねん")     }     if rs[len(rs)-1] == 'ん' || rs[len(rs)-1] == 'ン' {         return "", errors.New("出直して来い")     }     s, err := shiritori(text)     if err != nil {         return "", err     }     if s == "" {         return "", errors.New("わかりません")     }     rs = []rune(s)     if rs[len(rs)-1] == 'ん' || rs[len(rs)-1] == 'ン' {         s += "\nあっ..."     }     return s, nil } func main() {     fdk.Handle(fdk.HandlerFunc(myHandler)) } type Siritori struct {     Word string `json:"word"` } func myHandler(ctx context.Context, in io.Reader, out io.Writer) {     var s Siritori     json.NewDecoder(in).Decode(&s)     var err error     s.Word, err = handleText(s.Word)     if err != nil {         s.Word = err.Error()     }     json.NewEncoder(out).Encode(&s) }
辞書ファイルは statik を使ってバイナリに埋め込みました。ソースコードは GitHub に置いておきます。
mattn/oracle-cloud-function-siritori https://ift.tt/36bOlEp
デプロイは以下の手順で行います。
$ fn  --verbose deploy --app [your-app]
デプロイが完了すると標準入力で JSON を受け取り、標準出力で JSON を出力するコマンドが動く様になっています。
Tumblr media
VCN を作らないといけない事に気付くまで結構時間を使ってしまったけど、動く事が分かってからは結構サクサク操作できる様になりました。これだけ遊んでもまだ無料範囲内らしいので、もう少し遊んでみたいと思います。
Tumblr media
Oracle Cloud Pocket Solutions Guide (English Edition) Charles Kim, Jerry Ward, Sudhir Balasubramanian, Nitin Vengurlekar / (2016-11-23)   発送可能時間:
from Big Sky https://ift.tt/2v8pgO1
2 notes · View notes