【问题标题】:Create a dynamic function创建动态函数
【发布时间】:2019-02-09 19:43:24
【问题描述】:

我需要在 Golang 中实现一个现有的逻辑。一般来说,它是这样的:

// Function receives an object with a variable type (struct)
func(dynObject interface{}) {

    var variableFunc ... // What should be here?

    // Some things to do depending on the input param type
    switch dynObject.(type) {
    case *objA:
        // do some job
    case *objB:
        // do some job
    }

    // ...
    // Creating and calculating some variables for the following loop
    // ...

    humans := []*Humans{ ....... }
    sum := []int{}

    for _, human := range humans {
        result := variableFunc(dynObject, human)
        sum = append(sum, result)
    }
}

如您所见 - 作为输入,有一个 dynObject,它是一个结构,但可以是一些预定义结构中的任何一个。后来有一个函数variableFunc,必须要取这个对象和进程,处理逻辑也要看类型。所以类型 objA 需要与 objB 不同的逻辑。

我不知道实现这一点的正常方法。如何创建这个动态函数,它可以将不同的结构作为输入并对其应用所需的逻辑?目前我得到一个错误,该函数需要另一种类型作为输入。我希望避免额外的 switch-case,因为已经存在一个。

当然,我尝试创建一个预定义的函数,并使用接口,然后以某种方式在现有的 switch-case 中重新定义它,但没有运气。我需要你的帮助

【问题讨论】:

  • 到目前为止,您正在创建一个接受接口的函数,并根据类型切换代码。您不应该收到任何类型的错误,“在我收到错误的那一刻,该函数需要另一种类型作为输入”,您可以复制粘贴您在这里遇到的错误吗?
  • 如果 variableFunc 是动态的,也许有助于查看它的伪代码或逻辑?抱歉,我不太明白你的意思。
  • @vdolez,我相信在这种情况下这并不重要,只是想象它们是不同的。比如objA需要objA.x+objA.y,而objB需要objB.z * 150 - objB.n
  • @Alexey,为什么?如果 variableFunc 是一个用于处理特定类型的函数,则可以通过对接口tour.golang.org/methods/15 进行类型断言来完成。另一方面,如果你在另一个动态函数中创建一个多接口变量类型函数,你最终会使用更多的 switch 语句。所以这里的问题是,封装函数和 variableFunc 都是“动态”的,还是封装函数是“静态的”,而 variableFunc 是“动态的”?
  • 你不能只为每个实现特定于结构的逻辑的结构(如DoWork()HandleHuman(*Human) int)添加两个函数吗?然后您还可以创建一个包含这些函数的接口,并且您的基函数可以采用该接口类型的参数。然后你所要做的就是调用这两个函数。这种方法也摆脱了第一个开关,因为您只需要调用DoWork() 函数。

标签: go


【解决方案1】:
package main

import "fmt"

func main() {
    common(4)
    common("whitespace")
}
func common(a interface{}) {
    switch a.(type) {
    case int:
        div(a.(int), 2)
        break
    case string:
        sayHello(a.(string))
        break
    default:
        //nothing
    }
    return
}
func div(a, b int) {
    fmt.Printf("%d", a/b)
    return
}
func sayHello(a string) {
    fmt.Printf("%s", a)
}

main 函数调用common 函数,这又调用了两个不同的函数,它们具有不同的函数签名。您可以看到他们执行不同的操作。所以这将为不同的输入打印不同的结果。如果在你的 switch 语句中调用不同的函数是你想要做的(我可以从你的 cmets 中收集到),那么应该这样做。告诉我。


在我的 switch-case 中有一项工作要做,然后它的结果被用来计算其他变量(在我的例子中是中间部分),然后我才调用 variableFunc()

package stackoverflow

import "fmt"

func common(a interface{}) {
    switch a.(type) {
    case int:
        defer func(b int) {
            fmt.Printf("%d \n", b/2)
        }(a.(int))
        break
    case string:
        defer func(b string) {
            fmt.Printf("hello %s \n", b)
        }(a.(string))
        break
    default:
        //nothing
    }

    //do something here
    fmt.Println("did something here test")
    // the function gets called after
    return
}

您可以使用延迟。因此,这不是 defer 的常规用法。但从技术上讲,它可以用于这样的事情。上述功能只有在//something 完成后才会执行,我相信这就是您所追求的那种灵活性。如果某些函数出现恐慌,则该语句将在执行和退出之间出现。所以,你必须知道你在做什么。


或者你也可以使用这个,以防你稍后有参数进来。

package stackoverflow

import "fmt"

func common(a interface{}) {
    var f func(interface{}, int)
    switch a.(type) {
    case int:
        f = func(s interface{}, b int) {
            fmt.Printf("%d and %d\n", s.(int)/2, b)
        }
        break
    case string:
        f = func(b interface{}, c int) {
            fmt.Printf("hello %s and %d \n", b.(string), c)
        }
        break
    default:
        //nothing
    }
    //do something here
    fmt.Println("did something here test")
    // the function gets called after
    var x int = 21

    f(a, x)

    return
}

【讨论】:

  • 关闭。但是你跳过了一些事情:在我的 switch-case 中有一项工作要做,然后它的结果被用来计算其他变量(在我的例子中是中间部分),然后我才调用variableFunc()。在您的示例中,我不能这么快调用div()sayHello(),因为并非所有需要的参数都是已知的。在我的情况下,这就像我希望至少避免第二次切换的 switch-case 之后的 switch-case。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-09
相关资源
最近更新 更多