質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

1回答

552閲覧

Goの構造体への値が代入できない

tetra_

総合スコア2

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2020/10/18 08:20

編集2020/10/18 09:09

前提・実現したいこと

現在Dialogflowを勉強しています。
Dialogflowのwebhookを利用してAPIを呼び出す処理を実装していますが、構造体に値を入れられず詰まっています。
ご教授宜しくお願いいたします
Dialogflow <-> CloudFunctions <-> NewsAPI

サーバサイドはGo言語になります。

詰まっていること
fulfillmentMessages.text.textに値を追加して行きたいのですがどの様に追加すれば良いのかが分かりません。
以下試したコードです。

for i := 0; i < len(newAPIResponse.Articles); i++ { response.FulfillmentMessages.Text.Text = append(response.FulfillmentMessages.Text.Text, newAPIResponse.Articles[i].Title) }

この場合JSONにエンコードすると以下の様になりました。

response

1{{["title title title title"]}} //一つの配列に全て入ってしまう

理想は以下の様な形です。

{ "fulfillmentMessages": [ { "text": { "text": [ "Text response from webhook", "Text response from webhook",       ...以下略 ] } } ] }

該当のソースコード

https://cloud.google.com/dialogflow/es/docs/fulfillment-webhook#requirements
DialogflowへのレスポンスJSON

fulfillmentMessages

1{ 2 "fulfillmentMessages": [ 3 { 4 "text": { 5 "text": [ 6 "Text response from webhook" 7 ] 8 } 9 } 10 ] 11}

ニュースAPIのレスポンスは以下の様になっています。

NewsAPI

1{ 2"status": "ok", 3"totalResults": 38, 4-"articles": [ 5-{ 6-"source": { 7"id": "cnn", 8"name": "CNN" 9}, 10"author": "Frank Pallotta, CNN Business", 11"title": "'SNL' takes on the dueling town halls between Trump and Biden - CNN", 12"description": "Instead of a presidential debate, this week had dueling town halls between President Donald Trump and former Vice President Joe Biden. \"Saturday Night Live\" covered both, like many viewers, by flipping back and forth between the two.", 13"url": "https://www.cnn.com/2020/10/18/media/snl-biden-trump-town-halls/index.html", 14"urlToImage": "https://cdn.cnn.com/cnnnext/dam/assets/201017234919-saturday-night-live-cold-open-super-tease.jpg", 15"publishedAt": "2020-10-18T04:22:00Z", 16"content": "New York (CNN Business)Instead of a presidential debate, this week had dueling town halls between President Donald Trump and former Vice President Joe Biden. \"Saturday Night Live\" covered both, like … [+2381 chars]" 17}, 18-{ 19-"source": { 20"id": null, 21"name": "NCAA.com" 22}, 23"author": "NCAA.com", 24"title": "Alabama dominates second half, beats Georgia 41-24 in huge SEC game - NCAA.com", 25"description": "No. 2 Alabama controlled the second half as the Tide defeated No. 3 Georgia 41-24 on Saturday. QB Mac Jones led a powerful offense and the defense shut down Georgia after halftime.", 26"url": "https://www.ncaa.com/live-updates/football/fbs/alabama-dominates-second-half-beats-georgia-41-24-huge-sec-game", 27"urlToImage": "https://www.ncaa.com/_flysystem/public-s3/images/2020-10/alabama-football-mac-jones_0.jpg", 28"publishedAt": "2020-10-18T03:42:12Z", 29"content": "Georgia has come about as close as you can get to beating Alabama in recent years. On Saturday, the Bulldogs get another chance.\r\nThree of the last four meetings have been classics. In 2012, Georgia … [+1495 chars]" 30}, 31.....以下略

以下Functionsにデプロイしようとしている関数になります。
CloudFunctionsは(勉強予定)無理やり使っているので関数が肥大化してますが、許してください。

// Package p contains an HTTP Cloud Function. package p import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" ) type intent struct { DisplayName string `json:"displayName"` } type parameters struct { Where []string `json:"where"` } type queryResult struct { Intent intent `json:"intent"` Parameters parameters `json:"parameters"` } type text struct { Text []string `json:"text"` } type message struct { Text text `json:"text"` } type webhookRequest struct { Session string `json:"session"` ResponseID string `json:"responseId"` QueryResult queryResult `json:"queryResult"` } type webhookResponse struct { FulfillmentMessages message `json:"fulfillmentMessages"` } type NewsAPIResponse struct { Articles []articles `json:"articles"` } type articles struct { Title string `json:"title"` Url string `json:"url"` UrlToImage string `json:"urlToImage"` } // HandleWebhookRequest handles WebhookRequest and sends the WebhookResponse. func HandleWebhookRequest(w http.ResponseWriter, r *http.Request) { var request webhookRequest var response webhookResponse var err error var newAPIResponse NewsAPIResponse // Read input JSON if err = json.NewDecoder(r.Body).Decode(&request); err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "ERROR: %v", err) return } log.Printf("Request: %+v", request) // Call intent handler intent := request.QueryResult.Intent.DisplayName if intent == "News" { where := request.QueryResult.Parameters.Where if where[0] == "日本" { where[0] = "ja" } else if where[0] == "アメリカ" { where[0] = "us" } url := "https://newsapi.org/v2/top-headlines?country=" + where[0] + "&apiKey=*****" resp, _ := http.Get(url) defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err := json.Unmarshal(body, &newAPIResponse); err != nil { log.Fatal(err) } if err != nil { return } for i := 0; i < len(newAPIResponse.Articles)-1; i++ { //ここでどう代入するかが分かりません。 response.FulfillmentMessages.Text.Text[i] = newAPIResponse.Articles[i].Title } } if err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "ERROR: %v", err) return } log.Printf("newsresponse : %v", response) // Send response if err = json.NewEncoder(w).Encode(&response); err != nil { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintf(w, "ERROR: %v", err) return } }

試したこと

append関数を使って代入しましたが、一つのtextに全て代入してしまったので上手く行きませんでした。
append {{["aaa aaa aaa aaa aaa"]}}
理想 {{["aaa","aaa","aaa","aaa"]}}

補足情報(FW/ツールのバージョンなど)

Go 1.13
GoogleCloudFunctions
Dialogflow

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yasutakatou

2020/10/18 08:39

newAPIResponse.Articles自体が構造体なので newAPIResponse.Articles = append(newAPIResponse.Articles, [追加したい構造体]) みたいなイメージなのですがやりたいこととしてあってますでしょうか?
toast-uz

2020/10/18 08:49

「構造体に値を入れられず詰まっている」の、詰まっている状態と、理想の状態を、それぞれ明記いただけますか?肝心のそれらが記載されずに「試したこと」のみ、試した状態と、理想の状態が書かれています。
tetra_

2020/10/18 09:02

yasutakatouさん すみません、かなり省略して書いてしまいましたがその通りです。 ちなみにレスポンスに代入したいので以下の様に実装しました。 response.FulfillmentMessages.Text.Text = append(response.FulfillmentMessages.Text.Text, newAPIResponse.Articles[i].Title)
tetra_

2020/10/18 09:03

toast-uzさん ご指摘有難うございます。 質問の方を修正します。
yasutakatou

2020/10/18 10:01

newAPIResponse.Articles = append(newAPIResponse.Articles, articles{Title: "aaa", Url: "bbb", UrlToImage: "ccc"}) こういう風に追加できると思うのですが、私の解釈があってないようですかね?
tetra_

2020/10/19 03:54

すみません、yasutakatouさんのやり方で代入できました。 追加で質問したいのですが、mesaageが配列の場合appendで代入する場合どの様に実装すれば良いでしょうか for i := 0; i < len(newAPIResponse.Articles); i++ { response.FulfillmentMessages.Text.Text = append(response.FulfillmentMessages.Text.Text, newAPIResponse.Articles[i].Title) } だと response.FulfillmentMessages.Text undefined (type []message has no field or method Text) とエラーを吐かれます。 またFulfillmentMessages[0]で指定しても上手く行かないです。
yasutakatou

2020/10/19 04:26

FulfillmentMessagesの構造体ってtext.textで小文字ではないでしょうか? 他の部分はあってそうに見えますが。。
guest

回答1

0

完全にAPI処理を再現しているわけではありませんので、何か違っているかもしれませんが、「試したコード」でうまく動いているように思います。

入力となるnewAPIResponseは静的に与え、出力はhttp.ResponseWriterに書かずにjson.Marshalでバイト列にして、表示させて確認しています。質問者様のコードで同様に表示させて確認してみてください。

Go

1package main 2 3import ( 4 "encoding/json" 5 "fmt" 6) 7 8type text struct { 9 Text []string `json:"text"` 10} 11 12type message struct { 13 Text text `json:"text"` 14} 15 16type webhookResponse struct { 17 FulfillmentMessages message `json:"fulfillmentMessages"` 18} 19 20type typeNewsAPIResponse struct { 21 Articles []articles `json:"articles"` 22} 23 24type articles struct { 25 Title string `json:"title"` 26} 27 28func main() { 29 var response webhookResponse 30 31 newAPIResponse := typeNewsAPIResponse{[]articles {{Title: "title1"}, {Title: "title2"}, {Title: "title3"}, {Title: "title4"}}} 32 33 for i := 0; i < len(newAPIResponse.Articles); i++ { 34 response.FulfillmentMessages.Text.Text = append(response.FulfillmentMessages.Text.Text, newAPIResponse.Articles[i].Title) 35 } 36 37 data, _ := json.Marshal(&response) 38 fmt.Println(string(data)) 39} 40

結果

{"fulfillmentMessages":{"text":{"text":["title1","title2","title3","title4"]}}}

投稿2020/10/18 14:24

toast-uz

総合スコア3266

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tetra_

2020/10/19 04:20

回答有難うございます。 自分のコードで正常に動作していました。お騒がせしました。 追加で質問したいのですが、mesaageが配列の場合appendで代入する場合どの様に実装すれば良いでしょうか for i := 0; i < len(newAPIResponse.Articles); i++ { response.FulfillmentMessages.Text.Text = append(response.FulfillmentMessages.Text.Text, newAPIResponse.Articles[i].Title) } だと response.FulfillmentMessages.Text undefined (type []message has no field or method Text) とエラーを吐かれます。 またFulfillmentMessages[0]で指定しても上手く行かないです。
toast-uz

2020/10/19 09:41

ご質問意図がよく分かりません。返り値のmessageを配列にするということは、内側のtextと二重の配列になります。ところが入力側はarticlesしか配列が無いですよね。どうやって入力を出力に変換するのでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問