为什么控制器中的Revel可选函数参数不起作用?CRUD代码冗余。

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

Why are Revel optional func parameters in controller not working? CRUD code redundancy

问题

我看到你在谈论Go语言的可选参数和默认值的问题。在Go中,方法和函数不能有可选参数或某些参数的默认值。你举了一个简单的CRUD(创建、读取、更新和删除)的例子。

你想要在创建和更新操作中使用同一个控制器方法,并且只需简单地执行以下操作:

func (c Account) User(user models.User, verifyPassword string, id ...int64) {

    /*
    验证用户等等
    */
    if len(id) > 0 {
        c.Txn.Update(&model)
    } else {
        c.Txn.Insert(&model)
    }
}

当我在模板中尝试使用{{ url "Account.User" }}时,会出现缺少参数的错误。一旦我为路由硬编码数值,就会在代码的某个未知部分出现无效的内存地址或空指针引用。

如果没有可选/默认参数,我将不得不在CRUD操作中重复编写代码,这是我不想要的!

所以,我需要为同一件事情使用两个函数,它们只在一行代码上有所不同。

由于我七天前开始学习Go和Revel,也许我错过了什么。我使用Go和Revel的唯一原因是速度。我正在为一个每天有数百万次请求的项目使用它。

有没有办法解决这个问题?

更新

首先问题出现在视图中的{{ url "Account.User" }}

当我像这样使用它时,它会显示:

在 func (c Account) User(user models.User, verifyPassword string, id ...int64) 中,路由 Account.User 缺少参数 id

所以这更像是一个Revel的问题,而不是Go的问题。

英文:

I was reading lot about Go and see that I cannot have optional parameters (nor default value for some parameters) in methods or functions.
Lets take for example simple CRUD.

I want to use same controller action for create and update and just to do simple:

func (c Account) User(user models.User, verifyPassword string, id ...int64) {

    /*
    validate user etc
   */
    if len(id) > 0 {
        c.Txn.Update(&model)
    } else{
        c.Txn.Insert(&model)
    }
}

When I try to do {{ url "Account.User" }} in a template,
I get an error saying that I am missing parameters.
Once I hardcode value for route, I have some invalid memory address or nil pointer dereference on an unknown part of code.

Without optional/default parameters I will have code redundancy for CRUD that I do not want!

So instead of one function I will have to use two functions for the same thing that are only different in one line of code.

Since I started learning Go and Revel seven days ago, maybe I've missed something.
The only reason I used Go and Revel is for speed.
I am using this for some project that has a lot of requests (millions per day).

Is there any way to solve this?

Update

First problem is on the view: {{ url "Account.User" }}

When I used it like this, it says:

missing parameter id for route Account.User in func (c Account) User(user models.User, verifyPassword string, id ...int64)

So this is more of a Revel problem then Go.

答案1

得分: 0

有很多方法可以解决这个问题,就像其他问题一样。简单明显的解决方案(适用于任何语言)是将公共逻辑移入一个辅助方法,并提供两个包装器,分别接受不同的参数。话虽如此,我认为这并不必要,而且实际上无法理解你的问题,因为你的代码运行得很好...下面的示例程序清楚地显示了你可以使用0个或多个参数调用该方法,并根据参数的数量决定要执行的操作。

package main

import "fmt"

func main() {
    Test()
    Test(1)
    Test(1, 2)
    Test(1, 2, 3, 4)
}

func Test(numbers ...int) {
    fmt.Println(len(numbers))
}

我猜测你的意图是,如果提供了一个id(如果有id,则表示存在记录),则进行更新操作,否则进行插入操作。我还猜测你对如何调用该方法感到困惑,而不是如何定义它。你的定义看起来很好,并且应该按照你的意图正常工作,只要你正确调用它即可。最后,我认为你可能误用了...语言特性。如果id的长度预期为1或0,并且你正在使用可变长度数组作为真正可选参数的替代,那么你可能应该停止这样做。你可以只使用两个参数,一个布尔值表示“更新”,一个整数表示id。如果update为false,则调用update并且不传递id。

英文:

There are many ways to solve this problem, like any other. The simple obvious solution (which works in any language) would be to move the common logic into a helper method and provide two wrappers around it that accept different arguments. That being said, I don't think it's necessary and can't actually understand what your problem is because your code works just fine... My example program below clearly shows you can call the method with 0 or more arguments and decide what to do based on how many are present.

package main

import "fmt"

func main() {
	Test()
	Test(1)
	Test(1, 2)
	Test(1, 2, 3, 4)
}

func Test(numbers ... int) {
	fmt.Println(len(numbers))
}

I would guess your intent is to update if there is an id provided (if there's an id then it would indicate there is an existing record) and do insert if it is not. My other guess is that you're confused about how to call the method, not how to define it. Your definition looks fines and should work how you intend it to so long as you call it correctly. Finally, I think you're probably misusing the ... language feature. If the length of id is intended to be 1 or 0 and you're using that variable length array thing as a substitute for real optional parameters, you probably should stop doing that. You could just use 2 arguments, a bool saying 'update' and an int for id. If update is false, you call update and don't pass the id.

答案2

得分: 0

或者你可以尝试使用可变参数解析,就像Python中使用*args一样。

func (c Account) User(args ...interface{}) {

    for _, arg := range args {
        switch v := arg.(type) {
        case models.User:
            // 验证用户
        case string:
            // 验证密码
        case []int64:
            if len(v) > 0 {
                c.Txn.Update(&model)
            } else {
                c.Txn.Insert(&model)
            }
        default:
            // 一些默认操作
        }
    }
}

这段代码使用了可变参数args,通过switch语句对参数进行类型判断,并根据不同的类型执行相应的操作。在case models.User中,可以对用户进行验证;在case string中,可以对密码进行验证;在case []int64中,根据切片的长度进行更新或插入操作;在default中,可以执行一些默认的操作。

英文:

Or you can try variadic arguments parsing, like how Python uses *args

func (c Account) User(args ...interface{}) {

    for _, arg := range args {
        switch v := arg.(type) {
        case models.User:
            // validate user
        case string:
            // verify password
        case []int64:
            if len(v) > 0 {
                c.Txn.Update(&model)
            } else {
                c.Txn.Insert(&model)
            }
        default:
            // some default stuff
        }
    }
}

huangapple
  • 本文由 发表于 2015年6月9日 07:26:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/30720677.html
匿名

发表评论

匿名网友

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

确定