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

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

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

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

Q&A

解決済

4回答

2082閲覧

golang のswitchで複数当てはまる場合の複数実行の方法を教えてください

退会済みユーザー

退会済みユーザー

総合スコア0

Go

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

0グッド

0クリップ

投稿2017/07/30 14:04

#環境
golang1.8.3
gogland

#質問

go

1package main 2import ( 3 "fmt" 4 "regexp" 5) 6 7func main() { 8 messageType := []string{"check", "on", "off"} //スライス作成 9 10 re1 := regexp.MustCompile(messageType[0]) //checkをコンパイル 11 re2 := regexp.MustCompile(messageType[1]) //onをコンパイル 12 re3 := regexp.MustCompile(messageType[2]) //offをコンパイル 13 14 message := "on and off" //on, offの2つが入っている文字列 15 16 switch { 17 case re1.MatchString(message): //messageにcheckが含まれていた場合 18 fmt.Print("check") 19 20 case re2.MatchString(message): //messageにonが含まれていた場合 21 fmt.Print("on") 22 23 case re3.MatchString(message): //messageにoffが含まれていた場合 24 fmt.Print("off") 25 26 default: //その他の時 27 fmt.Print("I cant understand what you mean") 28 } 29}

このコードは、スライスの中身が変数messageに入っていたらcaseの中を処理するコードなのですが、messageの中に、2つ入っている場合、おそらくcaseで上に来ているonの中が処理された後にswitch構文から抜けると思います。

上記のように、caseの複数が該当する時に、二つの処理をさせるためにはどうすればいいですか?

#####関連した別件
上記のコードで、

go

1re1 := regexp.MustCompile(messageType[0]) //checkをコンパイル 2re2 := regexp.MustCompile(messageType[1]) //onをコンパイル 3re3 := regexp.MustCompile(messageType[2]) //offをコンパイル

となっている部分なんですが、forを使って簡潔に書く方法があれば教えていただきたいです。


例えば以下のようにすると変数reが上書きされてしまうと思います。。
変数名にiを関連付ければなんとかなる気もしますが、スマートな方法があればと思います。。

go

1i := 0 2for _, i range messageType{ 3 re := regexp.MustCompile(messageType[i]) 4 if i == 3{ break } 5 i++ 6}

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

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

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

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

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

guest

回答4

0

ベストアンサー

要件を整理すると作らないといけない物が分かると思います。

  • パターンAにマッチした場合はメッセージ a を表示する
  • パターンBにマッチした場合はメッセージ b を表示する
  • パターンCにマッチした場合はメッセージ c を表示する
  • いずれにもマッチしなかった場合にはメッセージ d を表示する

この要件には少なくとも条件マッチが 4 ついるのが分かるかと思います。switch で書くと A または B または C またはそれ以外という記述になるため、switch は向いていない、というのが理解できるかと思います。それぞれ独立した条件なので「いずれか」を実現するのであればループで回すしかなく、かつどれにもマッチしなかった場合も処理を書く事になります。

以下、元のソースと大きく変わってしまいますが、僕であればこう書くというのを載せておきます。

go

1package main 2 3import ( 4 "fmt" 5 "regexp" 6) 7 8var matchTypes = []struct { 9 pattern string 10 message string 11 re *regexp.Regexp 12}{ 13 { 14 pattern: "check", 15 message: "check にマッチしました", 16 }, 17 { 18 pattern: "on", 19 message: "on にマッチしました", 20 }, 21 { 22 pattern: "off", 23 message: "off にマッチしました", 24 }, 25} 26 27func init() { 28 for i := 0; i < len(matchTypes); i++ { 29 matchTypes[i].re = regexp.MustCompile(matchTypes[i].pattern) //コンパイル 30 } 31} 32 33func main() { 34 source := "on and off" //on, offの2つが入っている文字列 35 36 found := false 37 for _, m := range matchTypes { 38 if m.re.MatchString(source) { 39 fmt.Println(m.message) 40 found = true 41 } 42 } 43 if !found { 44 fmt.Print("I cant understand what you mean") 45 } 46}

この形の方が後からパターンを追加する場合等にも見通しが良く、またテストを作る際にも役立ちます。switch 文だとテストケース作るの大変ですからね。

投稿2017/08/02 13:27

mattn

総合スコア5030

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

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

退会済みユーザー

退会済みユーザー

2017/08/18 05:01

構造体を使うことでパターンと処理を紐づけてるんですね! 処理の部分を関数などにすると応用することができますね! とても綺麗です。ありがとうございました!
退会済みユーザー

退会済みユーザー

2017/08/18 20:05

これ、messageの部分を即時関数などにしたい場合はどうすればいいですか? message stringの部分の型を関数の場合どう表記すればいいのかわかりません
guest

0

caseの複数が該当する時に、二つの処理をさせるためにはどうすればいいですか?

こちらに関しては、switchで実現しないほうが簡単かもしれません。
switch(切り替える)という意味からも分かる通り、どれか一つの処理を実行させたい場合に向いています。

また、部分一致があるかないかを判定するときにMatchStringを使うのは最適ではないでしょう。
今回の場合はstrings.Contains()でいいかと思われます。

https://play.golang.org/p/EVmmV1f_Wl

go

1func main() { 2 messageType := []string{"check", "on", "off"} //スライス作成 3 message := "on and off" //on, offの2つが入っている文字列 4 5 contain := false 6 for _, v := range messageType { 7 if strings.Contains(message, v) { 8 // メッセージに特定の文字が含まれていたら特定の文字を出力する 9 fmt.Print(v, " ") 10 contain = true 11 } 12 } 13 if !contain { 14 // 何も含まなければ見つからなかったことを表示して伝える 15 fmt.Print("I cant understand what you mean") 16 } 17}

一応、正規表現版も
https://play.golang.org/p/2kjrZB_lqK

投稿2017/08/03 03:27

intelf___

総合スコア868

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

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

退会済みユーザー

退会済みユーザー

2017/08/18 04:59 編集

ベストアンサーを決めた後に回答をくださったため気がつくことができませんでした。 初心者の僕でもわかりやすい回答だと感じました。 strings.Contains()という便利な関数があることも知りませんでした。 他にも他人のコードを読んでいると、メッセージごとの処理をファイルで分けてHandlerにセットして云々というようなものもありました。 わざわざありがとうございました。
guest

0

go

1message := "on and off" 2msgFields := strings.Fields(message) 3 4for _, v := range msgFields { 5 switch { 6 case re1.MatchString(v): 7 // 処理 8 } 9}

for文とswitch文を合わせて使えば、できるかと思います。

投稿2017/08/01 02:13

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

mattn

2017/08/02 13:21

switch の意味がないですね。
退会済みユーザー

退会済みユーザー

2017/08/02 13:38

この場合if文を使っても同じ結果が出ると思いますが、私はswitchの方が読みやすいのでswitchを使いました。 if-else-if-elseの代わりに使うとコードが読みやすくなると思います。 https://golang.org/doc/effective_go.html#switch
mattn

2017/08/02 14:09 編集

switch が if の代わりに書けるのは知っています。(もう7~8年もgoを書いていますからね) 今回の要件は「パターンAにマッチしていればメッセージ a を表示する」という物なので、条件を書いたtしても if-else-if-else にはならなく if-else しかないのです。switch で書くと case 1つと default になります。なお条件にマッチしてループを止めたい場合、switch の場合は labeled goto を使わないと抜けられなくなります。 このコードにはいずれの条件にもマッチしなかった場合、という物がありません。
退会済みユーザー

退会済みユーザー

2017/08/02 14:14

私が条件をちゃんと理解してなかったかもしれませんが、質問の内容は「caseの複数が該当する時に、二つの処理をさせるためにはどうすればいいですか?」と書いてあって、for文と条件文を合わせたコードを書きました。
guest

0

fallthroughを使うとswitchから抜けません。

golang

1case re1.MatchString(message): //messageにcheckが含まれていた場合 2 fmt.Print("check") 3 fallthrough

投稿2017/07/30 14:44

kokardy

総合スコア781

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

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

退会済みユーザー

退会済みユーザー

2017/07/30 15:57

fallthroughを使うと、caseで条件分岐するのではなく、したのcase内部の処理を問答無用で行ってしまいます。(自分の環境ではそうなりました。) 全部実行したいのではなく、caseの条件がtrueの時だけ実行したいです。 switchをやめて大人しくifで条件分岐するしかないのでしょうか...
kokardy

2017/07/31 16:18

各caseでtrueの時だけなら、大人しくというかifで書くのが正当だと思います。 十分スマートです。 条件が多かったらre1,re2,re3をスライスにして、 for i := 0 ; i < len(re) ; i++{ re[i] = MatchString(message) } としてもいいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問