如何在Go语言中避免使用长的switch-case语句

huangapple go评论118阅读模式
英文:

How to avoid a long switch-case statement in Go

问题

我正在使用Go语言编写一个聊天机器人,想知道如何避免类似于这样的长switch-case语句:

switch {
    // @bot search me HMAC
    case strings.Contains(message, "search me"):
        query := strings.Split(message, "search me ")[1]
        return webSearch(query), "html"

    // @bot thesaurus me challenge
    case strings.Contains(message, "thesaurus me"):
        query := strings.Split(message, "thesaurus me ")[1]
        return synonyms(query), "html"
}

我应该将这些处理程序分别定义在单独的包中,还是只使用结构体和接口?哪种方法能够让我拥有良好的结构,避免switch-case,并让外部开发人员更容易创建处理程序?

我认为使用包会是一个更好的选择,但我不确定如何将处理程序注册到主要的机器人中。希望能够给出一个示例。

英文:

I'm writing a chat bot in Go and wondering how can I avoid a long switch-case statement similar to this one:

switch {

// @bot search me HMAC
case strings.Contains(message, "search me"):
	query := strings.Split(message, "search me ")[1]
	return webSearch(query), "html"

// @bot thesaurus me challenge
case strings.Contains(message, "thesaurus me"):
	query := strings.Split(message, "thesaurus me ")[1]
	return synonyms(query), "html"

Should I define those handlers each in a separate package or should I just use structs and interfaces? Which method will allow me to have a good structure, avoid switch-case and let external developers to easier create handlers?

I think packages will be a better choice but I'm not sure how to register the handlers with the main bot. Would appreciate an example.

答案1

得分: 11

你可以使用类似于net/http包注册处理程序的map[string]command。类似于以下示例代码:

package main

import (
	"fmt"
	"errors"
)

type BotFunc func(string) (string, error)

type BotMap map[string]BotFunc

var Bot = BotMap{}

func (b BotMap) RegisterCommand(command string, f BotFunc) error {
	if _, exists := b[command]; exists {
		return errors.New("command already exists")
	}
	b[command] = f
	return nil
}

func (b BotMap) Execute(statement string) (string, error) {
	// parse out command and query however you choose (not this way obviously)
	command := statement[:9]
	query := statement[10:]

	return b.ExecuteQuery(command, query)
}

func (b BotMap) ExecuteQuery(command, query string) (string, error) {
	if com, exists := b[command]; exists {
		return com(query)
	}
	return "", errors.New("command doesn't exist")
}

func main() {
	err := Bot.RegisterCommand("search me", func(query string) (string, error) {
		fmt.Println("search", query)
		return "searched", nil
	})
	if err != nil {
		fmt.Println(err)
		return
	}
	err = Bot.RegisterCommand("thesaurus me", func(query string) (string, error) {
		fmt.Println("thesaurus", query)
		return "thesaurused", nil
	})
	if err != nil {
		fmt.Println(err)
		return
	}

	result, err := Bot.Execute("search me please")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(result)
}

显然,这里缺少了很多检查,但这是基本的思路。

英文:

You could use a map[string]command similar to how the net/http package registers handlers. Something akin to this:

https://play.golang.org/p/9YzHyLodAQ

package main
import (
"fmt"
"errors"
)
type BotFunc func(string) (string, error)
type BotMap map[string]BotFunc
var Bot = BotMap{}
func (b BotMap) RegisterCommand(command string, f BotFunc) error {
if _, exists := b[command]; exists {
return errors.New("command already exists")
}
b[command] = f
return nil
}
func (b BotMap) Execute(statement string) (string, error) {
// parse out command and query however you choose (not this way obviously)
command := statement[:9]
query := statement[10:]
return b.ExecuteQuery(command, query)
}
func (b BotMap) ExecuteQuery(command, query string) (string, error) {
if com, exists := b[command]; exists {
return com(query)
}
return "", errors.New("command doesn't exist")
}
func main() {
err := Bot.RegisterCommand("search me", func(query string) (string, error) {
fmt.Println("search", query)
return "searched", nil
})
if err != nil {
fmt.Println(err)
return
}
err = Bot.RegisterCommand("thesaurus me", func(query string) (string, error) {
fmt.Println("thesaurus", query)
return "thesaurused", nil
})
if err != nil {
fmt.Println(err)
return
}
result, err := Bot.Execute("search me please")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(result)
}

Obviously there's a lot of checks missing here, but this is the basic idea.

huangapple
  • 本文由 发表于 2017年6月29日 04:50:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/44812324.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定