我对连续错误进行了以下处理:
nodes, err := model.AllNodes()
if err != nil { // This error handling
pr := progressRes{ // is Just a copy of
Type: progressResponse, // error handling
Message: err.Error(), // for the next error,
MessageType: errorMessage, // what is the
Progress: 100, // best practice
} // to avoid
go response(ws, pr.json()) // repeating myself here
return // without making the code
} // complicated
links, err := model.AllLinks()
if err != nil {
pr := progressRes{
Type: progressResponse,
Message: err.Error(),
MessageType: errorMessage,
Progress: 100,
}
go response(ws, pr.json())
return
}
在不使代码复杂的情况下,避免在上面的代码中重复自己的最佳做法是什么?我可以考虑添加一个新的func
,但我只是觉得可能有一个更好的想法,我不知道。
答案 0 :(得分:1)
如果要在多个位置重复多个步骤,正确的方法是将这些步骤抽象为一个过程,这就是编程的内容。这适用于错误处理以及程序的任何其他部分。
一个选项:
func allNodesAndLinks() ([]*Node, []*Link, error) {
nodes, err := model.AllNodes()
if err != nil {
return nil, nil, err
}
links, err := model.AllLinks()
if err != nil {
return nil, nil, err
}
return nodes, links, nil
}
// ...
nodes, links, err := allNodesAndLinks()
if err != nil {
pr := progressRes{
Type: progressResponse,
Message: err.Error(),
MessageType: errorMessage,
Progress: 100,
}
go response(ws, pr.json())
return
}
另一种选择:
func respondWithError(ws io.Writer, err error) {
pr := progressRes{
Type: progressResponse,
Message: err.Error(),
MessageType: errorMessage,
Progress: 100,
}
response(ws, pr.json())
}
// ...
nodes, err := model.AllNodes()
if err != nil {
go respondWithError(ws, err)
return
}
links, err := model.AllLinks()
if err != nil {
go respondWithError(ws, err)
return
}
答案 1 :(得分:1)
您可以使用两种不同的方法; defer
或者,正如您所建议的那样,使用其他功能。
Defer会像这样工作:
// All of these must be defined before we call defer.
var err error
var progressResponse string
var errorMessage string
defer func() {
// Since the deferred function will be called even if
// the function has completed successfully, we need to
// check that there actually has been an error before we
// create the error response.
if err == nil {
return
}
pr := progressRes{
Type: progressResponse,
Message: err.Error(),
MessageType: errorMessage,
Progress: 100,
}
go response(ws, pr.json())
}()
nodes, err := model.AllNodes()
if err != nil {
// The deferred function will automatically be called here.
return
}
links, err := model.AllLinks()
if err != nil {
// And in every other place where the function returns.
return
}
这里的问题是可能存在一些与变量阴影相关的陷阱。举个例子:
var err error
defer func() {
if err != nil {
handleError(err)
}
}()
if a, err := doSomething(); err != nil {
return
}
以下是概念验证on the playground。
这里的问题是err
子句中的if
与上限范围内的a
不同;如果您在较高的范围内声明=
,并使用单个作业:=
而不是声明func a() {
links, err := b()
if err != nil {
pr := progressRes{
Type: progressResponse,
Message: err.Error(),
MessageType: errorMessage,
Progress: 100,
}
go response(ws, pr.json())
return
}
}
func b() ([]Link, error) {
nodes, err := model.AllNodes()
if err != nil {
return nil, err
}
links, err := model.AllLinks()
if err != nil {
return nil, err
}
// you probably then do something with nodes and links?
return resolveLinks(nodes, links)
}
,那么works as expected。可变阴影是一个常见的陷阱,特别是对初学者而言; further reading
因此,我通常使用和推荐的方法是具有另一种功能。调用者通常只需要一个实际的返回参数,因此它通常不会变得非常复杂。
dict.update()
答案 2 :(得分:1)
我首选的方法,因为它使单元测试比其他建议更容易,将是:
func doStuff() {
if err := doStuffWithError(); err != nil {
pr := progressRes{
Type: progressResponse,
Message: err.Error(),
MessageType: errorMessage,
Progress: 100,
}
go response(ws, pr.json())
return
}
}
func doStuffWithError() error {
nodes, err := model.AllNodes()
if err != nil {
return err
}
links, err := model.AllLinks()
if err != nil {
return err
}
// Do something with nodes and links
return nil
}