英文:
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 &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
}
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 < 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
}
}
答案1
得分: 2
由于Go语言不鼓励方法的重载,所以重复性是否可接受取决于实际的代码和任务。如果列出一个客户与列出多个客户非常不同(即需要不同的信息和具有不同的呈现逻辑),我认为这里的重复性并不是那么糟糕,因为差异可能会在将来变得更大,所以一个DRY(Don't Repeat Yourself)的解决方案可能会迅速变成一个if
和switch
的混乱(我在一个非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 notgetFoo
, so I usedcustomers
in my example. You would most probably call it asDB.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 thefunc foo()
notation, since it's more idiomatic and generally easier togrep
. EDIT: as OP pointed out in the comments, another case forvar 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论