简化Go代码

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

Simplifying Go Code

问题

我有两个函数如下所示,它们看起来很相似,但使用不同的函数来查询数据库。由于Go语言不鼓励方法重载,重复性是否可接受?或者应该将它们重构为一个函数?欢迎所有的评论。

var getCustomers = func() ([]customer, error) {
    return nil, nil
}

var getCustomerById = func(int64) (*customer, error) {
    return nil, nil
}

func listCustomer(w http.ResponseWriter, r *http.Request) *appError {
    cus, err := getCustomers()
    if err != nil {
        return &appError{err, "No customer found", 404}
    }

    res, err := json.Marshal(cus)

    if err != nil {
        return &appError{err, "Can't display record", 500}
    }

    fmt.Fprint(w, string(res))
    return nil
}

func viewCustomer(w http.ResponseWriter, r *http.Request, id int64) *appError {
    cus, err := getCustomerByID(id)
    if err != nil {
        return &appError{err, "No customer found", 404}
    }

    res, err := json.Marshal(cus)

    if err != nil {
        return &appError{err, "Can't display record", 500}
    }

    fmt.Fprint(w, string(res))
    return nil
}

建议使用-1来列出所有客户,但我不确定这是否是最好的解决方案:

func viewCustomer(w http.ResponseWriter, r *http.Request, id int64) *appError {
    var c *customer
    var clist []customer
    var err error

    if id < 0 {
        clist, err = getCustomers()
        res, err := json.Marshal(clist)

        if err != nil {
            return &appError{err, "Can't display record", 500}
        }

        fmt.Fprint(w, string(res))
        return nil
    } else {
        c, err = getCustomerById(id)
        res, err := json.Marshal(c)

        if err != nil {
            return &appError{err, "Can't display record", 500}
        }

        fmt.Fprint(w, string(res))
        return nil
    }
}
英文:

I have two functions as shown below which look similar, but using different functions to query the db. Since Go doesn't encourage overloaading methods, is the redundancy acceptable? Or should I refactor them into one function? All comments are welcomed.

var getCustomers = func() ([]customer, error) {
    return nil, nil
}

var getCustomerById = func(int64) (*customer, error) {
    return nil, nil
}

func listCustomer(w http.ResponseWriter, r *http.Request) *appError {
	cus, err := getCustomers()
	if err != nil {
		return &amp;appError{err, &quot;No customer found&quot;, 404}
	}

	res, err := json.Marshal(cus)

	if err != nil {
		return &amp;appError{err, &quot;Can&#39;t display record&quot;, 500}
	}

	fmt.Fprint(w, string(res))
	return nil
}

func viewCustomer(w http.ResponseWriter, r *http.Request, id int64) *appError {
	cus, err := getCustomerByID(id)
	if err != nil {
		return &amp;appError{err, &quot;No customer found&quot;, 404}
	}

	res, err := json.Marshal(cus)

	if err != nil {
		return &amp;appError{err, &quot;Can&#39;t display record&quot;, 500}
	}

	fmt.Fprint(w, string(res))
	return nil
}

Suggestion to use -1 to list all customer, but I'm not sure if this is the best it can be:

func viewCustomer(w http.ResponseWriter, r *http.Request, id int64) *appError {
    var c *customer
    var clist []customer
    var err error

    if id &lt; 0 {
        clist, err = getCustomers()
        res, err := json.Marshal(clist)

     	if err != nil {
    		return &amp;appError{err, &quot;Can&#39;t display record&quot;, 500}
	    }

     	fmt.Fprint(w, string(res))
    	return nil
    } else {
        c, err = getCustomerById(id)
        res, err := json.Marshal(c)

     	if err != nil {
    		return &amp;appError{err, &quot;Can&#39;t display record&quot;, 500}
	    }

     	fmt.Fprint(w, string(res))
    	return nil
    }
}

答案1

得分: 2

由于Go语言不鼓励方法的重载,所以重复性是否可接受取决于实际的代码和任务。如果列出一个客户与列出多个客户非常不同(即需要不同的信息和具有不同的呈现逻辑),我认为这里的重复性并不是那么糟糕,因为差异可能会在将来变得更大,所以一个DRY(Don't Repeat Yourself)的解决方案可能会迅速变成一个ifswitch的混乱(我在一个非Go项目上有过类似的经历,从那时起我认为DRY是好的,但你不应该对它过于狂热)。

另一方面,如果你正在创建一个JSON API,你可以使其更加DRY。像这样定义你的getCustomers函数:

func customers(ids ...int64) ([]customer, error) { /* ... */ }

这样你可以:

  • 调用customers()来获取所有客户;
  • 调用customers(42)来获取ID为42的客户;
  • 调用customers(someIDs...)来根据ID获取多个客户。

所有这些都可以在一个处理程序中以直接的方式完成。

关于你的代码,有两个小问题:

  • 在Go中,getter方法的惯用命名方式是foo而不是getFoo,所以我在示例中使用了customers。你很可能会这样调用它:DB.Customers(ids...),所以它看起来很像一个getter方法。
  • var foo = func()这种写法是怎么回事?除非有理由这样做(比如将这些函数用作闭包),否则我建议坚持使用func foo()的写法,因为它更符合惯例,而且通常更容易进行grep搜索。**编辑:**正如评论中的OP指出的,var foo = func()写法的另一个情况当然是可以在测试中伪造的函数,就像Andrew Gerrand的Testing Techniques talk中所示。

希望对你有所帮助。

英文:

>Since Go doesn't encourage overloaading methods, is the redundancy acceptable? Or should I refactor them into one function?

The answer to your question depends heavily on the real code and your task. If listing one customer is very different from listing several customers (that is, you need different information and have different presentation logic), I'd say that duplication here is not that bad, since the difference may grow larger in the future, so a DRY solution could turn into an if and switch mess quickly. (I've had a similar experience on a non-Go project and since then I think that DRY is good but you should not be fanatic about it.)

On the other hand, if you're making, say a JSON API, you could make it more DRY. Define your getCustomers function like this:

func customers(ids ...int64) ([]customer, error) { /* ... */ }

This way you can:

  • call it like customers() and get all customers;
  • call customers(42) and get a customer whose ID is 42;
  • call customers(someIDs...) and get multiple customers by their IDs.

All can be done in one handler in a straightforward way.

>All comments are welcomed.

Two nitpicks on your code:

  • Getter methods in Go are idiomatically named foo and not getFoo, so I used customers in my example. You would most probably call it as DB.Customers(ids...), so it looks a lot like a getter method.

  • What's up with var foo = func() notation? Unless there is a reason for that (like using these functions as closures), I'd suggest sticking with the func foo() notation, since it's more idiomatic and generally easier to grep. EDIT: as OP pointed out in the comments, another case for var foo = func() notation is of course functions that can be faked in testing, as shown in Andrew Gerrand's Testing Techniques talk.

I hope that helps.

huangapple
  • 本文由 发表于 2014年9月20日 17:15:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/25947211.html
匿名

发表评论

匿名网友

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

确定