Goでinterface{}を扱うときの忘備録:型コンバートについて
昨日(2014/12/23)同期とあつまりハッカソン的ななにかを開催したのですが、
お題もとくに決まってなかったのでhipchatのapiを使って遊んでいたので、
その中で学んだことの忘備てきななにかです。
hipchatのAPIについては上記の公式ドキュメントを見ると
様々な言語で作成された便利なライブラリなどがあります。
今回はその中で私が現在勉強しているGoのclient libraryを使ってみることにしました。
履歴の出力時に学んだこと
特定の部屋の会話履歴を最高30件分取得して、
とくに加工整形せずに出力する場合は下記のようなコードを書きます。
c := hipchat.NewClient(authToken string) historyRq := &hipchat.HistoryRequest{MaxResults: 30} history, _, err := c.Room.History(room_name string, historyRq) if err != nil { log.Fatal(err) } for _, item := range history.Items { fmt.Println(item) }
そのままの内容を載せることはできないので加工してありますが出力結果はこんな感じ
{2014-12-23Thh:mm:ss.0123456+00:00 map[id:012345 links:map[self:https://api.hipchat.com/v2/user/012345] mention_name:test name:TestUser] abcdefg-1234567-a12b3c4d [] テスト message} {2014-12-23Thh:mm:ss.0123456+00:00 map[id:012345 links:map[self:https://api.hipchat.com/v2/user/012345] mention_name:test name:TestUser] abcdefg-1234567-a12b3c4d [] テストテスト message}
これはhistory.Itemsからmessage構造体の配列を受け取り
各message構造体の要素を出力しています。要素の詳細は下記リンク参照
hipchat - GoDoc
とにかく分かり難い。履歴の中でほしい情報は発言者の名前とその内容。
他には時間くらいだと思います。
そこで加工整形して出力するようにしたところ発言内容はitem.Messageとして簡単に取り出せました。
ただし発言者の名前の要素がmessage構造体のFromにあり
Fromの型がinterface{}型という問題にぶち当たり、思うままに結果を取り出せませんでした。
以下のようにしても発言者の名前は取り出せず。。。
for _, item := range history.Items { fmt.Printf("%s :%s",item["name"],item.message) }
型のコンバート
そこでいろいろ調べたところinterface{}の型を
コンバートするとnameを取り出せるところにたどり着きました。
map[id:012345 links:map[self:https://api.hipchat.com/v2/user/012345] mention_name:test name:TestUser]
上記は先ほどの出力からFromの部分のみを抜き出したもの
コンバートするために最初はmap[string]stringかなと思い下記のようにして実行しました。
from := item.From.(map[string]string)
しかし、正しく動作せずに出力されたエラーにはmap[string]interface{}の文字が。
どうやらFromはmap[string]interface{}にコンバートできるようでした。
そこで下記のようにしたところ実際に動作しました。
from := item.From.(map[string]interface{})
Fromの形式が様々問題
しかしこれで全てが解決したわけではありませんでした。
なんとFromのコンバートができないitemが存在しました。
詳しく調べたわけではないのですがおそらくbotからのpostの場合は
Fromにある情報がnameだけのようでした。
そこでコンバートを実行した場合に成功の可否を受け取ることができたので、
下記のように実装しました。
for _, item := range history.Items { var from map[string]interface{} var ok bool if from,ok = item.From.(map[string]interface{}); ok { fmt.Printf("%s :%s\n",from["name"],item.Message) }else{ fmt.Printf("%s :%s\n",message.From,item.Message) } }
これにより出力結果は「発言者の名前:発言内容」というようになりました。
以上ざっくり自分メモと素振りの成果。
Perl入学式を地方で開催してみたというお話
はじめに
この記事はPerl入学式アドベントカレンダー20日目の記事です。
Perl入学式ではたまにサポータをやっております。タケウチです。
現在は東京、大阪、福岡の3都府県で開催されているPerl入学式の歴史についてはpapix校長が下記リンク先で綴っております。
2014年12月02日 : Perl入学式 公式ブログ
2014年12月09日 : Perl入学式 公式ブログ
2014年12月18日 : Perl入学式 公式ブログ
ですが、おそらくこの歴史の中で出て来ることはないであろう、簡易出張版Perl入学式in釧路について
今回は書いていきたいと思います。
田舎でPerl入学式
そもそもpapix校長とは現在の会社の内定者時代に知り合いそこでPerl入学式というものを知り、
当時のwebサイトを見たりしていました。
そこでは以前からPerl入学式で使用している資料が公開されていて、勉強には絶好の題材でした。
最初は独学で学んでいたのですが、ちょうどその頃私が参加していたITコミュニティで言語を一つ勉強したいという話があがっていました。そこで私はPerl入学式の資料を使ってみんなで勉強するチャンスだと思い早速提案しました。
もちろんpapix校長に資料の使用について確認をしてから使用しました。
そこからPerl入学式の資料を使わせていただきながらの勉強会を3、4回ほど開催したころ、
papix校長を北海道に呼ぼう計画が私のなかでふと、起こり本人に打診、実際に校長来道ということになりました。
勉強会では簡易出張版Perl入学式としてAPIクライアントの開発というテーマで開催することができました。
下記はpapix校長の開催感想ブログです。
釧路で「Perl入学式出張版」をやってきた - Masteries
さてここまで書いてきましたが、言いたかったことは一つ。
東京、大阪、福岡だけでなく北海道の片田舎でもPerl入学式は開催できました!
せっかくPerl入学式の素晴らしい資料が公開されているので、もちろん参加した人が復習などに使うのはもちろんですが、既存の入学式に参加するのが地理的に困難な人たちが集まって、自分たちで開催することは可能です!
また声を上げれば校長がやってくる!?
そして簡易版が開催できる!?
ということで以上で今日の記事はここまでです。
明日はぼくの尊敬する先輩の担当ということでとても楽しみです!
それではまたPerl入学式で楽しく学びましょう!
Goでテストを実行する時の備忘録
Goでテストを回すには
最近Goで実装するものがあった。そこでテストを回すときの自分メモ兼今日の素振りの成果
とりあえず下記公式のページでTestingの箇所を見れば大まかにわかる
How to Write Go Code - The Go Programming Language
公式ページではリモートリポジトリに対するテストもやっているが今回はローカルに対してのみ
例としては以下のようなパッケージ構成を想定する
fizzbuzz |-- fizzbuzz.go |-- fizzbuzz_test.go
またfizzbuzz_test.goの内容は以下のように想定
package fizzbuzz import( "testing" ) func TestFizz(t *testing.T){ ... } func TestBuzz(t *testing.T){ ... }
作成しているパッケージ内でまるっとテストを回すときは以下のようにする
> go test PASS ok fizzbuzz 123.456s
テストを1つずつ結果を見ながらすすめる
> go test -v === RUN TestFizz --- PASS: TestFizz (xxx.xx seconds) === RUN TestBuzz --- PASS: TestBuzz (xxx.xx seconds) PASS ok command-line-arguments xxx.xxxs
その他の実行方法
複数ファイルの場合
次の例として以下のように細かくファイルが分かれている場合
fizzbuzz |-- fizz.go |-- fizz_test.go |-- buzz.go |-- buzz_test.go
対象ファイルを指定して実行
> go test fizz.go fizz_test.go
自分がやってしまったミス
> go test fizz_test.go
上記の場合テストは以下のようにテストを実装する必要がある。ただしこのテストはどうなんだろう
package fizzbuzz import( "testing" "fizzbuzz" ) func TestFizz(t *testing.T) { fizzbuzz.Fizz() ... }
パッケージが階層でわかれている場合
fizzbuzz |--fizz | |-- fizz.go | |-- fizz_test.go |-- buzz.go |-- buzz_test.go
以下のようにすると再帰的にテストを実行する
> go test ./...
YAPC::Asiaに初参加、あとLTしてきた #yapcasia
今更ですが8月29、30日の2日間開催されていたYAPC::Asiaに初めて参加してきまた。またLTしてきました。
1日目は参加することができなかったので、2日目からの参加でした。
当日は午前中から会場にいたのですがとても緊張していたので発表を聴きにいってもあまり頭に入ってきませんでした。
なので公開されている発表動画で復習してます。
以下に当日行ったLTのスライド載せておきます。
すぐ緊張するたちで、さらに会場は満員状態。
伝えたいことがちゃんとみなさんに伝わったか不安だったのですが、感想などをいただくと概ね伝わったかなと思いました。
最後になりましたが、運営スタッフのみなさまへYAPC初参加でしたがとても楽しかったです。ありがとうございました!
WordCount実装でGolang入門
久しぶりの更新は技術ネタです。
Golangはじめました
ちょうど勉強会でGolangの話を聴いて興味がわいたので触ってみた。
まずA Tour of Goというブラウザだけで学習できるチュートリアルから始めてみた。
その中で41ページ目(この表現であってるか微妙だが)にある、WordCount関数の実装問題がGolangの実装の入門にちょうど良いなと思った。
WordCount関数
func WordCount(s string) map[string]int { return map[string]int{"x": 1} }
これがWordCount関数の初期状態。引数は文字列1つ。
キーが文字列で要素が数値のmapが返り値となっている。
とりあえず実装
下記はこの実装問題にたどり着くまでに行った演習と問題ページにあるヒントから単純に書いた回答。
これでも問題なく動作する。
func WordCount(s string) map[string]int { str := strings.Fields(s) m := make(map[string]int) for i := range str { m[str[i]] += 1 } return m }
Golangでは『var hoge string = "fuga"』のように
var宣言、変数名、型、初期化子というように変数を宣言する。
また関数内では以下のように『:=』でvarの代わりに暗黙的な型宣言で代入ができる。
関数内だしvar宣言して書かなくていいならこっち使おうという安直な考えで記述。
str := strings.Fields(s) m := make(map[string]int)
Golangでは繰り返し文はforのみ。
条件はwhileのような書き方もできる。また条件を指定しないと無限ループになる。
また今回のようにrangeを使うことで変数のインデックス分繰り返すといった処理ができる。
ここでも『:=』で代入。そしてループが終了するとmを返す。
for i := range str { m[str[i]] += 1 } return m
リファクタリング
一度はこれで良いかと思ったが、動けば良いというものでは全く勉強にならない。
そこで改めて自分のコードを書き直してみた。
まず初めにword_mapというキーが文字列で要素が数値のmapを返すことを明示した。
func WordCount(s string) (word_map map[string]int) {
次に『:=』では『strings.Fields(s)』が何を返すのかリファレンスを見なければ確認できなかった。
そこで一目で分かるようにvar宣言、変数名、型、初期化子という形で記述した。
var str []string = strings.Fields(s)
rangeを使うと実は変数からインデックスと値の両方が返ってくる。
今回は処理的にインデックスは不要だった。
そこで『_』に代入することでインデックスを破棄し、値のみをループの中で使用した。
最後にreturnだけで終了してるが、前述の通りword_mapという
キーが文字列で要素が数値のmapを返すことを明示しているのでこの一行で終了することができる。
for _,key := range str { word_map[key] += 1 } return
以下はここまで説明したものを一つにまとめたものである。
一番最初に提示した回答例と違い、処理内容が初見でも理解しやすくなっていると思う。
func WordCount(s string) (word_map map[string]int) { var str []string = strings.Fields(s) word_map = make(map[string]int) for _,key := range str { word_map[key] += 1 } return }
こうして一つ一つを理解していくなかでとくに『_』を使ったインデックスの破棄や、
最初に変数名と型を宣言しておくことで『return』と書くだけでその値が返ることなど面白いなと感じた。
今後の学習予定
とりあえずA Tour of Goを完了させる。
また今週末から来週にかけてGolangの勉強会に3回ほど参加する予定なのでとても楽しみだ。
上京しました
久しぶりの更新。とりあえず近況報告。
就職に伴い上京しました。
以下からは今まで参加したけどアウトプットできていなかった、北海道でのコミュニティ活動参加記録。
時期で言うと昨年末から3月までのまとめ。
昨年末
LOCAL学生部の総大会に参加してきました。札幌市内で1泊2日の開発合宿でした。
当日の宿
ぼくは後輩にPerl入学式の資料を使いながら、レクチャーをして2日間過ごしていました。
また同時にDMMWebAPIとMojoliciousを使って商品のフリーワード検索ができるサイトを構築しました。
2日目の成果発表では後輩が自分が学んだ成果をしっかりと発表している姿を見て嬉しく思いました。
LOCAL学生部の活動では道内の様々な学校の方々と交流ができ、とくにtomioやがるとの出会いが
ぼくのコミュニティ活動をさらに楽しくしてくれました。
釧路活動記【釧路 Advent Calendar 2013】
はじめに
この記事は釧路 Advent Calendar 2013の12月7日分の記事です。
6日のtomioの記事でさんざんdisられハードルを日高山脈ほどにあげられたタケウチが担当します。
今回の主旨
ぼくは帯広出身で釧路に住み始めたのは高専入学してからなので今年で7年目です。
住み始めてから4年くらいは釧路の端っこの大楽毛からほとんど出ずに生活してました。
なので今回は大楽毛から出ていろいろ行動するようになった、
釧路生活5年目から現在に至るまでを書きます。
釧路での生活
勉強会への参加
釧路生活5年目くらいから釧路OSSコミュニティ(以下釧路OSS)の活動に参加しています。
釧路OSSについては前日までの記事でちらほら出てきていますし、
今後の記事でも出てくると思うので割愛しますが、ぼくが学生のうちに社会人の方々との
コミュニケーションの取り方について学べる場でした。
勉強会
今まで大楽毛近辺でしか活動せず、腐りかけていたぼくは勉強会に参加することで、
外に目を向ける事ができました。
道内だと北見や札幌、旭川のイベントに参加。また道外に出て東京などに行きいろいろな人と会い、
お話をすることで視野がどんどん広くなっていきました。
釧路でモチベーションを保つ難しさ
釧路生活6年目からは高専カンファレンスというイベントの企画、運営などの
活動にも積極的に参加するようになりました。
しかしこの頃から外に出て釧路に戻ってきた時なんとも言い表せない気持ちになることがありました。
そしてこの現象は7年目の現在も続いています。
簡単に言ってしまえばモチベーションの低下ですが、もっとモヤモヤした気分になります。
未だに自分でどうしてこうなるのかはっきりとはわからないので解決できません。
なので応急処置的にモチベーションを上げるのに、
釧路でこういうイベントができたら良いななど考えたりしています。
おわりに
明日は釧路OSSでも活動されていた志村さんの登場です!
ぼくが書いたのは7年間の学生生活でしたが、社会人の方の7年間は
いったいどのような記事になるのかとても楽しみです!!
最後まで読んでいただきありがとうございました。