在方法声明中允许可变数量的返回值

时间:2016-08-27 03:30:29

标签: go

我有一个函数可以解决Go不允许在方法声明中设置默认值的问题。我想通过允许可变数量的返回变量来使它更好一些。我知道我可以允许一个接口数组作为返回类型,然后创建一个包含所有要返回的变量的接口数组,如下所示:

func SetParams(params []interface{}, args ...interface{}) (...[]interface{}) {
    var values []interface{}
    for i := range params {
            var value interface{}
            paramType := reflect.TypeOf(params[i])
            if len(args) < (i + 1) {
                    value = params[i]
            } else {
                    argType := reflect.TypeOf(args[i])
                    if paramType != argType {
                            value = params[i]
                    }
                    value = args[i]
            }
            values = append(values, value)
    }

    return values
}

这是您要为其定义默认值的方法的示例。您将其构建为可变参数函数(允许可变数量的参数),然后在函数内而不是在声明行中定义要查找的特定参数的默认值。

func DoSomething(args ...interface{}) {
    //setup default values
    str := "default string 1"
    num := 1
    str2 := "default string 2"


    //this is fine
    values := SetParams([]interface{str, num, str2}, args)
    str = values[0].(string)
    num = values[1].(int)
    str = values[2].(string)


    //I'd rather support this
    str, num, str2 = SetParams(params, args)
}

我理解

  

[] interface {str,num,str2}

上例中的

在语法上不正确。我这样做是为了简化我的帖子。但是,它代表了构建接口数组的另一个函数。

我想支持这个:

str, num, str2 = SetParams(params, args)

而不是必须这样做:

values := SetParams([]interface{str, num, str2}, args)
str = values[0].(string)
num = values[1].(int)
str = values[2].(string)

有什么建议吗?帮助

2 个答案:

答案 0 :(得分:3)

请不要写出可怕的(由于reflect)代码来解决不存在的问题。 如评论中所示,将语言转换为 您以前的一种语言确实引人注目 切换后,但这会适得其反。

相反,最好使用习语和方法 和语言提供的最佳实践 - 即使你不喜欢它们(但也许)。

对于这种特殊情况,你可以像这样滚动:

  • 制作想要接受的功能 具有默认值的参数列表 接受自定义struct类型的单个值。

  • 首先,任何此类型的变量在分配时, 将所有字段的所有字段初始化为所谓的“零值” 适合各自的类型。

    如果这就够了,你可以在那里停下来:你将能够 将struct类型的值传递给您的函数 通过在呼叫站点的文字生成它们 - 只初始化你需要的字段。

    否则有预处理/后处理代码 将为字段提供您自己的“零值” 你需要。

2016-08-29更新:

使用struct类型模拟可选参数 使用其字段分配发生的默认值 成为各自数据类型的Go的原始零值:

package main

import (
    "fmt"
)

type params struct {
    foo string
    bar int
    baz float32
}

func myfun(params params) {
    fmt.Printf("%#v\n", params)
}

func main() {
    myfun(params{})
    myfun(params{bar: 42})
    myfun(params{foo: "xyzzy", baz: 0.3e-2})
}

输出:

main.params{foo:"", bar:0, baz:0}
main.params{foo:"", bar:42, baz:0}
main.params{foo:"xyzzy", bar:0, baz:0.003}

如您所见,Go初始化params类型的字段 零值适合各自的类型 除非我们在定义文字时指定自己的值。

Playground link.

提供非Go-native零值的默认值 我们的自定义类型的字段可以通过预先完成 或者后处理用户提交的复合类型值。

后处理:

package main

import (
    "fmt"
)

type params struct {
    foo string
    bar int
    baz float32
}

func (pp *params) setDefaults() {
    if pp.foo == "" {
        pp.foo = "ahem"
    }
    if pp.bar == 0 {
        pp.bar = -3
    }
    if pp.baz == 0 { // Can't really do this to FP numbers; for demonstration purposes only
        pp.baz = 0.5
    }
}

func myfun(params params) {
    params.setDefaults()
    fmt.Printf("%#v\n", params)
}

func main() {
    myfun(params{})
    myfun(params{bar: 42})
    myfun(params{foo: "xyzzy", baz: 0.3e-2})
}

输出:

main.params{foo:"ahem", bar:-3, baz:0.5}
main.params{foo:"ahem", bar:42, baz:0.5}
main.params{foo:"xyzzy", bar:-3, baz:0.003}

Playground link.

预处理相当于创建“构造函数”功能 这将返回预填充所需类型的值 使用默认值选择其字段 - 某些内容 像这样:

func newParams() params {
    return params{
        foo: "ahem",
        bar: -3,
        baz: 0.5,
    }
}

以便您的函数的调用者可以调用newParams(), 如果需要调整其字段,然后传递结果值 你的职能:

myfunc(newParams())

ps := newParams()
ps.foo = "xyzzy"
myfunc(ps)

这种方法可能比后处理更有效但是 它排除了使用文字来构造要传递给的值 你在呼叫站点的功能不那么“整洁”。

答案 1 :(得分:0)

最近,我在Go中使用匿名函数,并实现了一个接受并返回未定义参数的示例:

func functions() (funcArray []func(args ... interface{}) (interface{}, error)) {

    type ret struct{
        first   int
        second  string
        third   bool
    }

    f1 := func(args ... interface{}) (interface{}, error){
        a := args[0].(int)
        b := args[1].(int)
        return (a < b), nil
    }
    funcArray = append(funcArray , f1)

    f2 := func(args ... interface{}) (interface{}, error){
        return (args[0].(string) + args[1].(string)), nil
    }
    funcArray = append(funcArray , f2)

    f3 := func(args ... interface{}) (interface{}, error){
        return []int{1,2,3}, nil
    }
    funcArray = append(funcArray , f3)

    f4 := func(args ... interface{}) (interface{}, error){
        return ret{first: 1, second: "2", third: true} , nil
    }
    funcArray = append(funcArray , f4)

    return funcArray 
}


func main() {

    myFirst_Function := functions()[0]
    mySecond_Function := functions()[1]
    myThird_Function := functions()[2]
    myFourth_Function := functions()[3]

    fmt.Println(myFirst_Function(1,2))
    fmt.Println(mySecond_Function("1","2"))
    fmt.Println(myThird_Function())
    fmt.Println(myFourth_Function ())

}

希望对您有帮助。

https://play.golang.org/p/d6dSYLwbUB9