akms道東

ITイベント,勉強会への参加記録や趣味のことが書いてあるブログです.

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)
    }
  }

これにより出力結果は「発言者の名前:発言内容」というようになりました。

以上ざっくり自分メモと素振りの成果。