@Linda_pp さんのツイートをみて
Go 言語の nil って NilLit じゃなくて Ident "nil" としてパースされるのか.それで気付いたけど nil := 42 みたいに普通に変数宣言できる(unused でエラーになるけど)
— ドッグ (@Linda_pp) 2018年11月22日 なるほど、これは面白い。 と少し遊んでみたメモ。
言語仕様にある通り、Goのキーワードは以下の25個です(Go1.11.2)。
break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var この一覧に nil や true, false は入っていません。 これらは builtinという扱いになっており、識別子として利用可能です。
そのため、変数名等に利用可能というわけですね。面白い。
package main import ( "fmt" ) func main() { nil := 42 fmt.Println(nil) // Output: // 42 } 以下、色々遊んでみた例。
必要に迫られて作りました。 PHPでエンコードしたJSONをいい感じにデコードしてくれるGoのパッケージです。
shogo82148/go-phper-json 背景 さて、PHPerの方々には当たり前のことかもしれませんが、PHPの言語仕様について少しおさらいです。 それがどうしてGoで問題になるか見ていきます。
PHPのarray問題 PHPはとても便利なプログラミング言語なので、配列を扱うことができます。 ここでPHPの配列のマニュアルを読んでみましょう。
http://php.net/manual/ja/language.types.array.php
PHP の配列は、実際には順番付けられたマップです。マップは型の一種で、 値をキーに関連付けます。 この型は、さまざまな使い道にあわせて最適化されます。 配列としてだけでなく、リスト (ベクター)、 ハッシュテーブル (マップの実装の一つ)、辞書、コレクション、スタック、 キュー等として使用することが可能です。 PHP の配列には他の PHP 配列を値として保持することができるため、 非常に簡単にツリー構造を表現することが可能です。 (強調部分は筆者によるもの)
重要なことなのでもう一度。
配列としてだけでなく、リスト (ベクター)、 ハッシュテーブル (マップの実装の一つ)、辞書、コレクション、スタック、 キュー等として使用することが可能です。
他の言語でリスト、ハッシュテーブル、辞書等と呼ばれているものは、PHPにおいてはいずれも配列です。 PHPにとっては、整数を添字にしているか、文字列を添字にしているかの違いでしかありません。 (PHP7.xから整数が添字の場合に最適化が入るようになったらしいけど、大きな挙動の変更はないはず)
そのため、以下のスクリプトは true を返します。
<?php $a = array("apple", "banana"); $b = array(0 => "apple", 1 => "banana"); var_dump($a == $b); // bool(true) この仕様のため、JSONにエンコードすると最初は配列だったのに、 処理を進めていくうちにうっかり文字列のキーを作ってしまって、 JSONのオブジェクトに変わってました、ということが起こりえます。 Goにおいて両者は全く違う型なので、デコードの際に非常に困ります。
<?php $a = array(1, 2, 3); print json_encode($a); // [1,2,3] $a["foo"] = "bar"; print json_encode($a); // {"0":1,"1":2,"2":3,"foo":"bar"} このような悲劇を防ぐために、 JSON_FORCE_OBJECT というオプションがあるのですが、 オプションの名前通りに全部JSONのオブジェクトになってしまいます。 この要素だけJSONの配列にして欲しい!といった細かな操作はできません。
僕は知っています。
ぜひ、みなさんもお手元の電波時計で試してみてください!
と書いても、試してくれる人なんていないことを。
僕は知っています。
説明書や仕様書に書いてあったとしても、書いてあるとおりに動作する機械なんて、ほんの一握りだということを。
というわけで、楽しい夏休みの自由研究です。 秋葉原で適当に買った1000円から3000円くらいの電波時計に、サマータイムのフラグを有効にした電波を受信させてみて、どういう挙動になるか調査してみました。
TL;DR 10機種(SEIKO, CITIZEN, CASIO, MAG, ELECOM, その他)に対して、サマータイムフラグを有効にした状態で Web JJY の電波を送信しました。
今回の調査範囲では、夏時間の時刻(1時間 or 2時間ズレた時刻)を表示する時計は見つからなかった 夏時間実施中(DST)と表示 する時計は実在する 室内で使うならCASIOの電波時計はクオーツ時計だと思ったほうがいい 電波受信の様子をYouTubeにあげておいたので興味のある方はどうぞ。
背景 2018年、日本は記録的な猛暑に見舞われ、 観測史上最高の気温41.1度を記録し、 熱中症とみられる症状で90人以上が亡くなるという甚大な被害を被った。
今週の天気 記録的な猛暑 底知れぬ暑い夏 日本で猛暑 気温41.1度で観測史上最高 気象庁「災害と認識」熱中症死の疑い6日で90人超 この記録的猛暑を受け、政府・与党によって2020年の東京五輪・パラリンピックの酷暑対策として、夏の期間だけ時間を2時間繰り上げる「サマータイム(夏時間)」の導入が検討されている。
酷暑対策でサマータイム導入へ 秋の臨時国会で議員立法 31、32年限定 これに対して、「電波時計が狂うのではないか」「日本中の電波時計がゴミになる」等、電波時計が正しい時刻を示さなくなるとの指摘が相次いでいる。
サマータイム導入で「電波時計が狂う」? メーカーに聞いた サマータイムで日本中の電波時計がゴミになる(かも)という話 電波時計は、NICT(情報通信研究機構)が提供している標準電波(JJY)を受信し、時刻の同期を行っている。 この標準電波には、時、分、通算日、年、曜日といったタイムコード情報に加え、 将来の拡張性のための「予備ビット」が設けられている。 この予備ビットに関して、「標準電波の出し方について」には、夏時間情報として意味を持たせる場合の例が記載されているが、これはあくまでも例であり、告示などで正式に決まっているものではない。 しかし、現実に市販されている電波時計のなかにも、仕様上予備ビットの状態を認識する機種がする。
標準電波の送信周波数40kHzを提供する「おおたかどや山標準電波送信所」は1999年6月運用開始、送信周波数60kHzを提供する「はがね山標準電波送信所」は2001年10月運用開始である。 日本でサマータイムが導入されたのは1948年から1951年の期間だけなので、 今後サマータイムが導入されることとなれば、標準電波の運用が始まってから初のサマータイム導入となる。
夏時刻法 - Wikipedia 長波帯標準電波施設 パンフレット(PDF) そのため、仕様上はサマータイムへ対応している電波時計であっても、初のサマータイム実施によって未知の挙動を示すことが十分に想定される。 そこで、本記事では、実際にサマータイム実施中の電波を電波時計に受信させ、 どのような挙動を示すのかを明らかにする。
目的 2018年8月現在日本で市販されている電波時計が、サマータイムの情報を含んだ標準電波(JJY)を受信した場合の挙動を調査し、 仮に、2019年、2020年にサマータイムが導入された場合の影響を明らかにする。
実験方法 秋葉原で購入した以下の電波時計に対して、標準電波と同様の電波を送信し、時刻の同期を行う。
CITIZEN 8RZ152 CITIZEN 4RL432-019 SEIKO SQ698S SEIKO KR331W MAG T-694 SM-Z ELECOM CLK-DD001RD 京都大和 171038 (製造元不明) 31756 CASIO DQD-710J-8JF CASIO TTM-160NJ-8JF 電波の送信には、Samsung Galaxy Note8 SC-01K を用いて、JJYシミュレータWeb版を実行する。
もうすぐリリースのGo1.11ではWebAssemblyのサポートが予定されています。 (2018/08/19現在の最新版はGo1.11rc1)
Go言語がWebAssemblyをサポートへ。GOARCHは「wasm」、GOOSは「js」に 正式リリース前に少し遊んでみようということで、@yuroyoroさんのGoAst ViewerをWebAssemblyへビルドしてみました。
GoAst Viewer WebAssembly Version shogo82148/goast-viewer JavaScriptの連携方法 コードをASTに変換し、JSONとしてエンコードする部分(ast.go)に関しては、一切変更しなくても動きました。素晴らしい。
ただし、さすがにブラウザ上でHTTPサーバーは動かない(そういえば試してないけど、動かないよね??)ので、JavaScriptとの連携部分を実装してあげる必要があります。 syscall/jsパッケージはまだ実験段階というステータスで機能が限られているので、 連携には少し工夫が必要です。
JavaScriptからGoの関数を呼ぶ JavaScriptからGoの関数を呼ぶには window にコールバック関数として必要な関数を登録します。
// GoASTParse 関数を定義(Go言語) js.Global().Set("GoASTParse", js.NewCallback(func(args []js.Value) { source := args[0].String() // ...ASTへの変換処理... })) 戻り値をGoからJavaScriptへ返す js.NewCallback なのですが、もともとは addEventListener にわたすコールバック関数なので、 関数の戻り値を受けわたす方法がありません。 回避方法はいろいろあるでしょうが、今回はコールバック関数の引数にコールバック関数指定してもらうことにしました。
// GoASTParse 関数を定義(Go言語) js.Global().Set("GoASTParse", js.NewCallback(func(args []js.Value) { source := args[0].String() // ...ASTへの変換処理... args[1].Invoke(string(body)) })) // GoASTParseを呼び出す(JavaScript) GoASTParse("package main; func main() {}", function(body) { // ASTの表示処理 }) まとめ Goのバイナリ全般に言えることですが、WASMになってもやっぱりサイズが大きい(3.5M)。 今後のパフォーマンス向上に期待です。
GoよりAngulerJSの方が難しかったʕ ゚皿゚ ʔ
サマータイムなんて日本人には関係ないと思っていた時期が僕にもありました。 ところが何やら日本にもサマータイムがやってくる動きがあるようです。
酷暑対策でサマータイム導入へ 秋の臨時国会で議員立法 31、32年限定 さて、長波JJY(市販の電波時計のための電波)には夏時間の情報が含まれています。 「将来の拡張性のための予備ビット」という扱いなので、対応している時計なんてないだろう、と思っていたら、 なんと対応している時計が存在しているらしいということを知りました。
その事実を確かめるため、Webブラウザを使って電波を出してみたで紹介した JJYシミュレータWeb版に夏時間を有効にするチェックボックスを追加しました。
CITIZEN 8RZ152 の動作例 夏時間への同期、完了しました 😂😂😂 pic.twitter.com/3tMcCYdXpP
— Ichinose Shogo (@shogo82148) 2018年8月9日 念の為書いておきますが、今は午前8時です
— Ichinose Shogo (@shogo82148) 2018年8月9日 DST(Daylight Saving Time)の表示が出て、夏時間に切り替わったことがわかりますが、なぜか6時間もズレています・・・。
もう、こんな時間だ……そろそろ寝よう……
???お前24時間表記だっただろ?どうしたんだ???
(今は20時です) pic.twitter.com/8PViLOaj85
— Ichinose Shogo (@shogo82148) 2018年8月10日 悲報 11日を迎えることができず pic.twitter.com/pw0k0Qo8RY
— Ichinose Shogo (@shogo82148) 2018年8月10日 もはや数字ではないものが出てきた。
まとめ 夏時間に対応した電波時計の存在は事実でした。 しかし、機種によっては挙動がおかしくなるようです(N=1)。
ぜひ、みなさんもお手元の電波時計で試してみてください!
JJYシミュレータWeb版 ※ 利用の結果生じた損害について、一切責任を負いません。
参考 標準電波の出し方について 酷暑対策でサマータイム導入へ 秋の臨時国会で議員立法 31、32年限定 Webブラウザを使って電波を出してみた サマータイムで日本中の電波時計がゴミになる(かも)という話 サマータイム導入で「電波時計が狂う」? メーカーに聞いた 「サマータイム導入はコンピュータシステム的に難あり」は本当か サマータイム実施は不可能である from UEHARA, Tetsutaro 僕もサマータイム実施は不可能だと思います・・・。
S3からファイルを落とすだけのツールを作りました。
s3cli-mini 目的 流行りのCD(継続的デリバリー)を実践するために、専用のデプロイツールをダウンロードする目的で作りました。
主なデプロイ先はAWSなので、デプロイ操作には awscli が必要です。 しかしCDに使用しているCircleCIが公式に提供しているコンテナイメージにはawscliがインストールされていません。 もちろん apt-get install awscli であとからインストールすることは可能ですが、そのぶんジョブの実行時間が長くなってしまいます。 また、インストールされる awscli のバージョンが古く、ローカル環境ではうまく動くけど、 CircleCI上では最新の機能が使えず失敗するということがありました。
そこでもう awscli を使うことは諦めて、Goで AWS API を叩いてデプロイするバイナリを作ってしまうことを考えました。 Goであればシングルバイナリでインストール可能で、CI/CD環境とローカルでバージョンが一致せず悩まされることはありません。 また並行処理が得意なので、デプロイの時間短縮も図れます。
しかし、このデプロイ用のバイナリをどこに置くか・・・プロジェクト固有の処理が入っているので外部には公開したくない。 かといってプライベートなS3バケットに置くと、ダウンロードに awscli が必要になってしまう・・・。 awscli を使うのは諦めたはずでは・・・という、いわゆる「鶏が先か、卵が先か」問題に陥ってしまいました。
そこでS3からのダウンロードの処理に特化したミニawscliが欲しくなって作成したのが s3cli-mini です。
使い方 現状v0.0.1でサポートしているのは cp コマンドのみです。 S3バケットからファイルをダウンロードしたり、S3バケットへファイルをアップロードしたり、 別のS3バケットへファイルを転送することができます。
# download from a S3 bucket s3cli-mini cp s3://your-bucket/foobar.zip . # upload to a S3 bucket s3cli-mini cp foobar.zip s3://your-bucket/ # copy the file from a S3 bucket to another S3 bucket.
Goの http.Transport には RegisterProtocol というメソッドが生えていて これを使うと、 HTTP以外のプロトコルを透過的に扱うことができます。 代表的なのは http.NewFileTransport で、これを使うと、file://path/to/file.txt みたいなURLでファイルにアクセスすることができます。 (Goオフィシャルの例) この仕組を使って、S3へのアクセスも透過的にできるようにしてみたので、メモ。
新しいプロトコルを作成するのは非常に簡単です。 http.RoundTripperインターフェースを実装し、リクエストに応答するレスポンスを作ってあげればいいだけです。 S3の場合以下のようになります。(エラー時の扱いが雑だけど・・・)
package main import ( "net/http" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" ) type s3RoundTripper struct { s3 *s3.S3 } func newS3RoundTripper(session *session.Session) http.RoundTripper { return &s3RoundTripper{ s3: s3.New(session), } } func (rt *s3RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { host := req.Host if host == "" { host = req.URL.Host } path := req.URL.Path ctx := req.Context() out, err := rt.
去年仕込んだネタが見つかってしまったので、macopy 構造体について一応解説。
https://t.co/mHq6oWY3rj
macopyさん構造体だったのか・・・
— serinuntius (@_serinuntius) 2018年5月14日 2021-05-25 追記
今はこの方法では動かないというツイートを見かけました。
これで出てくる "Goの文法を使った構造体のコピーを防ぐ方法" が動かなかった話ですが https://t.co/FpEnspIfmN このへんに書いてありました.重要なことはその型がstructであること,Lock だけでなく Unlockも実装されていることでした.https://t.co/zQc6T058Ip このように変更すると検知されました
— おりさの (@orisano) May 25, 2021 どうやら Go 1.11 から判定基準が 「sync.Locker を実装しているか」に変わっていたようです。 (修正コミット: c2eba53, Issue: #26165)
というわけで、 macopy 構造体を以下のように変更する必要があります。
type macopy struct{} func (*macopy) Lock() {} func (*macopy) Unlock() {} 追記ここまで
目的 深淵な理由で Go の構造体のコピーを禁止したい場合があると思います。 kuiperbelt のケースでは、sync/atomic パッケージを使ってフィールドを更新しているので、 フィールドへの読み書きは必ず sync/atomic パッケージを使わなければなりません。 sync/atomic パッケージを使わずに構造体をコピーするとレースコンディションが発生してしまうので、コピーを禁止する必要がありました。
// https://github.com/kuiperbelt/kuiperbelt/blob/e3c1432ed798716c8e88183518f9126951c227f3/stats.go#L20-L28 type Stats struct { connections int64 totalConnections int64 totalMessages int64 connectErrors int64 messageErrors int64 closingConnections int64 noCopy macopy } // atomic.
OctopressからHugoに乗り換えました。 以下のような理由からです。
Rubyの環境をメンテナンスし続けるのが面倒 最近Octopress自体の更新が滞っている ビルド時間が長い 一番最初の理由が大きくて、いつもビルドしていた環境を壊してしまって修復が面倒になってしまいました。 そこでようやく重い腰を上げて移行したというわけです。
移行手順 OctopressからHugoへの移行は先人たちがたくさんいるので、それを参考にします。
# 記事のコピー cp octopress-site/source/_posts/* hugo-site/content/post/ # 画像のコピー cp -r octopress-site/source/images/* hugo-site/static/images/ # 記事のタイムスタンプの形式を変える # Hugoでは、"2016-09-25T15:09:57"のような形式のタイムスタンプでないとパースに失敗します find . -type f -exec sed -i "" -e 's/date: \([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}\) \([0-9]\{2\}:[0-9]\{2\}\)$/date: \1T\2:00+09:00/g' {} \; パーマネントリンクを維持するために OctopressからHugoへ移行する方法 のRubyスクリプトを利用させていただきました。
dir = 'content/post/' Dir::foreach(dir) do |filename| if filename =~ /\.markdown$/ slug = filename.gsub(/\d{4}-\d{2}-\d{2}-/, '').sub('.markdown', '') puts "#{filename} : #{slug}" lines = [] File::open(dir + filename) do |f| f.each do |line| lines << line end end File::open(dir + filename, 'w') do |f| lines.
昨年の年末から Mackerel の本格導入を始めました。 それに当たって AWS Integration 用の CloudFormation テンプレートを書いたので、 他のプロジェクトでも導入が簡単になるよう公開しました。
shogo82148/cf_mackerel 使い方 GitHub Pages でテンプレートを公開しているので、 template-body にテンプレートのURLを指定して、 新しいスタックを作成するだけです。
aws cloudformation create-stack --stack-name "MackerelIntegrationIamUser" \ --template-body https://shogo82148.github.io/cf_mackerel/mackerel.yaml \ --capabilities CAPABILITY_NAMED_IAM 新しい名前付きIAMロールを作成するので CAPABILITY_NAMED_IAM が必要です。
作成がうまくいくとOutputに以下のようなARNが出力されるので、 MackerelのAWS Integrationの設定画面へ入力しましょう。
arn:aws:iam::xxxxxxxxxxxx:role/MackerelAWSIntegrationRole-ap-northeast-1 ロール名について ロール名が意図せずに変わってしまって連携が切れてしまうのを防ぐため、 ロール名は決め打ちです。
MackerelAWSIntegrationRole-ap-northeast-1
ロール名にリージョン名(この場合は ap-northeast-1)が含まれていますが、 作成されたロールはグローバルなリソースなので、他のリージョンでも使用可能です。 わざわざリージョン名含めているのは CloudFormation の警告にしたがったためです。
警告
IAM リソースに名前を付けると、複数のリージョンで同じテンプレートを再利用した場合に、回復不能なエラーが発生する場合があります。 これを防止するために、Fn::Join と AWS::Region を使用して、次の例のように地域固有の名前を作成することをお勧めします RoleName
回復不能なエラー!!
コワイので実際に何が起こるかは試してませんが、警告には素直に従っておくことにします。
参考 AWS::IAM::Role - AWS CloudFormation - mackerelのAWSインテグレーション用IAM Userをcloudformationで作る Tomohiro/tf_mackerel 同じことをするTerraformのモジュール