【问题标题】:Call functions with special prefix/suffix调用带有特殊前缀/后缀的函数
【发布时间】:2019-01-15 18:39:39
【问题描述】:

我有一个名为“seeder”的包:

package seeder

import "fmt"

func MyFunc1() {
    fmt.Println("I am Masood")
}

func MyFunc2() {
    fmt.Println("I am a programmer")
}

func MyFunc3() {
    fmt.Println("I want to buy a car")
}

现在我想调用所有带有 MyFunc 前缀的函数

package main

import "./seeder"

func main() {
    for k := 1; k <= 3; k++ {
        seeder.MyFunc1() // This calls MyFunc1 three times
    }
}

我想要这样的东西:

for k := 1; k <= 3; k++ {
    seeder.MyFunc + k ()
}

这个输出:

I am Masood
I am a programmer
I want to buy a car

EDIT1: 在这个例子中,parentKey 是一个在循环中改变的字符串变量

for parentKey, _ := range uRLSjson{ 
    pppp := seeder + "." + strings.ToUpper(parentKey)
    gorilla.HandleFunc("/", pppp).Name(parentKey)
}

但是GC说:

使用没有选择器的包播种器

【问题讨论】:

  • 嗨,马苏德。在您的子函数中,您不是说 Hello World 文本与函数不是全部 MyFunc1 匹配吗?:即 func MyFunc2() { fmt.Println("Hello MyFunc2") }
  • 好的,我看到你已经解决了这个问题。
  • 您好,我的意思是调用带有特殊前缀的函数。让我们将 fmt 输出更改为更清晰

标签: string function go


【解决方案1】:

你不能通过它的名字得到一个函数,这就是你想要做的。原因是如果 Go 工具可以检测到一个函数没有被显式引用(因此无法访问),它甚至可能不会被编译成可执行的二进制文件。详情见Splitting client/server code

带有函数注册表

一种方法是在调用它们之前构建一个“函数注册表”:

registry := map[string]func(){
    "MyFunc1": MyFunc1,
    "MyFunc2": MyFunc2,
    "MyFunc3": MyFunc3,
}
for k := 1; k <= 3; k++ {
    registry[fmt.Sprintf("MyFunc%d", k)]()
}

输出(在Go Playground上试试):

Hello MyFunc1
Hello MyFunc2
Hello MyFunc3

手动“路由”

类似于注册表是检查名称并手动路由到函数,例如:

func callByName(name string) {
    switch name {
    case "MyFunc1":
        MyFunc1()
    case "MyFunc2":
        MyFunc2()
    case "MyFunc3":
        MyFunc3()
    default:
        panic("Unknown function name")
    }
}

使用它:

for k := 1; k <= 3; k++ {
    callByName(fmt.Sprintf("MyFunc%d", k))
}

Go Playground 上试试这个。

注意: 是否要在callByName() 辅助函数中调用由其名称标识的函数由您决定,或者您可以选择返回函数值(func() 类型) 并在调用者的位置调用它。

将函数转换为方法

另外请注意,如果您的函数实际上是某种类型的方法,您可以在没有注册表的情况下执行此操作。使用反射,您可以通过名称获取方法:Value.MethodByName()。您还可以使用Value.NumMethod()Value.Method() 获取/枚举所有方法而不知道它们的名称(如果您需要方法的名称或其参数类型,请参见Type.NumMethod()Type.Method())。

这是可以做到的:

type MyType int

func (m MyType) MyFunc1() {
    fmt.Println("Hello MyFunc1")
}

func (m MyType) MyFunc2() {
    fmt.Println("Hello MyFunc2")
}

func (m MyType) MyFunc3() {
    fmt.Println("Hello MyFunc3")
}

func main() {
    v := reflect.ValueOf(MyType(0))
    for k := 1; k <= 3; k++ {
        v.MethodByName(fmt.Sprintf("MyFunc%d", k)).Call(nil)
    }
}

输出是一样的。在Go Playground 上试试吧。

【讨论】:

  • 谢谢,但是没有地图还有其他方法吗?
  • @MasoodAfrashteh 您可以使用注册表或将函数转换为方法来实现。有函数但没有注册表 - 你不能。
  • reflect,这有助于将字符串转化为功能。
  • @JiangYD 您无法使用reflect 获取函数名称,只能使用方法。
  • @MasoodAfrashteh 考虑到您对问题的编辑,答案仍然有效:如果没有注册表或使用方法而不是函数,您将无法做到这一点。
【解决方案2】:

另一种选择是覆盖你的函数数组

package main

import (
    "fmt"
)

func MyFunc1() {
    fmt.Println("I am Masood")
}

func MyFunc2() {
    fmt.Println("I am a programmer")
}

func MyFunc3() {
    fmt.Println("I want to buy a car")
}


func main() {
   for _, fn := range []func(){MyFunc1, MyFunc2, MyFunc3} {
        fn()
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 2012-08-04
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多