如何检查函数是否存在

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

go how to check if a function exists

问题

在Go语言中,可以通过使用反射来检查函数是否存在。以下是一个示例代码:

package main

import (
	"fmt"
	"reflect"
)

func someFunction() {
	fmt.Println("Hello, World!")
}

func main() {
	funcName := "someFunction"
	funcValue := reflect.ValueOf(funcName)
	if funcValue.Kind() == reflect.Func {
		fmt.Println("Function exists!")
	} else {
		fmt.Println("Function does not exist!")
	}
}

在上面的代码中,我们使用了reflect包来获取函数的值,并使用Kind()方法来检查该值的类型是否为函数。如果是函数类型,则说明函数存在。

请注意,由于Go语言的静态类型特性,函数的名称在编译时就已经确定,因此无法像PHP那样直接通过函数名称来检查函数是否存在。但是,通过使用反射,我们可以在运行时检查函数是否存在。

英文:

Is there any way to check if a func exists in Go?

In PHP I might do something like

if(function_exists('someFunction')) {
    //...
}

but I have not been able to figure out how to do this in Go

Any help on this will be greatly received.

答案1

得分: 6

更多关于你尝试做什么的背景信息会有所帮助。
正如你在自己的评论中提到的,如果你尝试调用一个函数,Go会在编译时检查该函数是否存在,大多数情况下都是如此。

我能想到的一个例外是当你使用interface{}并且在调用方法之前想要检查方法是否存在时。对于这种情况,你可以使用类型检查。

示例代码如下:

package main

import "fmt"

// 一个简单的Greeter结构体
// 定义了一个Hello()方法
type Greeter struct {
    Name string
}
func (m *Greeter) Hello() string {
    return "hello " + m.Name
}

var x interface{}

func main() {
    x = Greeter{Name: "Paolo"} // x是一个interface{}
    g, ok := x.(Greeter) // 我们必须检查x是否是一个Greeter...
    if ok {
        fmt.Println(g.Hello()) // ...在调用Hello()之前
    }
}

我能想到的另一种情况是你正在创建自己的Go工具,在编译之前需要解析Go文件。如果是这样,Go提供了parser包来帮助你。

英文:

A little more context on what you're trying to do would help.
As you note in your own comment, if you try to call a function Go checks at compile-time if the function exists, most of the times.

One exception that comes to my mind is when you use interface{} and you want to check that a method exists before calling it. For this you can use type checks.

Example:

package main

import "fmt"

// a simple Greeter struct
// with a Hello() method defined
type Greeter struct {
  	Name string	
}
func (m *Greeter) Hello() string {
	return "hello " + m.Name
}

var x interface{}

func main() {
	x = Greeter {Name:"Paolo"} // x is a interface{}
	g,ok := x.(Greeter) // we have to check that x is a Greeter...
	if ok {
		fmt.Println(g.Hello()) // ...before being able to call Hello()
	}
} 

Another scenario I can think of is that you're creating your own tool for Go that requires parsing go files before compiling them. If so, Go provides help in the for of the parser package

答案2

得分: 3

这是要翻译的内容:

无法这样做(而且是出于好的原因!)。原因是Go是一种编译语言,不支持可加载模块(至少目前还不支持),因此函数无法在运行时出现和消失,因此无论顶层函数是否存在,你都可以根据定义知道:如果给定的源文件import了包含所需函数的包<sup>1</sup>,那么该函数在该源文件中是可见的。或者该函数在与该源文件所属的包相同的包中声明,因此它也是可用的。在所有其他情况下,该函数是不可用的。请注意,一个函数可能在程序中被编译,但在编译给定的源文件时仍然不可见,因此你所说的可见性的整个定义在Go中是不存在的。

另一方面,你可能希望有一些通用性。在Go中,通过接口来实现通用性。你可以定义一个接口,然后要求某个类型实现它。检查类型是否实现了接口是通过一个巧妙的技巧来完成的。


2021年12月29日的更新。
在Go 1.8中,通过plugin包添加了对可加载模块的支持,并且自那时以来已经成熟,支持除Windows外的大多数主流平台。
然而,这种解决方案并非没有问题——例如,请参阅#20481


<sup>1</sup>除非将该模块重命名为空,但现在我们不要触及这个问题。

英文:

There's no way to do that (and for good!). The reason is that Go is a compiled language and does not support loadable modules (yet, at least) so functions can't come and go at runtime, and hence whether or not a top-level function exists, you know by defintion: if a given source file imports a package containing the function of interest<sup>1</sup>, that function is visible in this source file. Or this function is declared in the same package this source file belongs to and hence it's also available. In all the other cases the function is not available. Note that a function might be compiled in the program but still not visible in a given source file while compiling, so the whole definition of visibility as you put it does not exist in Go.

On the other hand you might want some generality. Generality in Go is achieved via interfaces. You might define an interface and then require a type to implement it. Checking that a type implements an interface is done via a neat trick.


An update from 2021-12-29.
The support for loadable modules was added in Go 1.8 in the form of the plugin package and has since then matured to support most mainline platforms except Windows.
Still, this solution is not without problems&mdash;for instance, see #20481.


<sup>1</sup>Without renaming that module to nothing, but let's not touch this for now.

答案3

得分: 1

如果你的东西是一个接口值,可以使用类型断言,类似这样:

if Aer, ok := thing.(interface{MethodA()}); ok {
  Aer.MethodA()
}

如果thing是一个结构体,首先将其赋值给一个接口变量,因为类型断言只适用于接口值。

定义一个命名接口而不是使用临时接口可能更好,但对于这种简单情况来说,这样做并不值得。

英文:

Provided your thing is an interface value, type assert, something like this:

if Aer, ok := thing.(interface{MethodA()}); ok { 
  Aer.MethodA() 
} 

If thing is a struct, assign it to an interface variable first,
because type assertions only work on interface values.

It wouldn't hurt to define a named interface instead of using the
nonce one, but for simple cases like this it's not worth it.

答案4

得分: 1

最近我需要弄清楚一个结构体是否具有特定的函数。以下是使用反射的另一种方法:

package main
     
import (
    "fmt"
    "reflect"
)

type FuncRegistry struct {}
  
func (fr FuncRegistry) Hi() {
    fmt.Println("function Hi")
}

func (fr FuncRegistry) Hello() {
    fmt.Println("function Hello")
}

func functionExists(obj interface{}, funcName string) bool { 
     mthd := reflect.ValueOf(obj).MethodByName(funcName)
     if mthd.IsValid() { 
         fmt.Printf("函数 '%s' 存在\n", funcName)
         return true 
     } 
     
     fmt.Printf("函数 '%s' 不存在\n", funcName)
     return false 
} 

// 主函数
func main() {
    var fr FuncRegistry
    functionExists(fr, "Hi")
    functionExists(fr, "Hello")
    functionExists(fr, "Fail")
}

希望对你有帮助!

英文:

Recently I had a need for figuring out if a struct has a particular function or not.
Here is another way using reflection :

package main
     
import (
    &quot;fmt&quot;
    &quot;reflect&quot;
)

type FuncRegistry struct {}
  
func (fr FuncRegistry) Hi() {
    fmt.Println(&quot;function Hi&quot;)
}

func (fr FuncRegistry) Hello() {
    fmt.Println(&quot;function Hello&quot;)
}

func functionExists(obj interface{},funcName string) bool { 
     mthd := reflect.ValueOf(obj).MethodByName(funcName)
     if mthd.IsValid() { 
         fmt.Printf(&quot;Function &#39;%s&#39; exists \n&quot;,funcName)
         return true 
     } 
     
     fmt.Printf(&quot;Function &#39;%s&#39; does not exist\n&quot;,funcName)
     return false 
} 

// Main function
func main() {
    var fr FuncRegistry
    functionExists(fr,&quot;Hi&quot;)
    functionExists(fr,&quot;Hello&quot;)
    functionExists(fr,&quot;Fail&quot;)
}

答案5

得分: -1

这听起来很像一个XY问题。请告诉我你想要做什么。据我所知,这不是像在PHP中那样可以完全做到的。

不过,你可以创建一个以函数名为键的映射。可以手动添加函数,或者在编译之前或运行时通过解析源文件来生成内容。不过,解析源文件似乎有点不太正规。

英文:

This sounds a lot like a XY problem. Please tell what you are trying to do. As far as I know, this is something you can't really do the same way as in PHP.

However, you could create a map with function names as keys. Add the functions there manually or generate the contents by parsing the source files before the compilation or at run time. Parsing the source seems like a dirty hack though.

huangapple
  • 本文由 发表于 2013年12月27日 18:29:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/20799028.html
匿名

发表评论

匿名网友

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

确定