我们可以在Go语言中使用函数指针吗?

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

Can we have function pointers in Go?

问题

我在学习Go语言中的指针。并且成功写出了类似以下代码的内容:

func hello(){

       fmt.Println("Hello World")
}

func main(){

       pfunc := hello     //pfunc是指向函数"hello"的指针
       pfunc()            //调用pfunc会打印"Hello World",与hello函数类似
}

有没有一种方法可以声明函数指针而不像上面那样定义它呢?
我们能否像在C语言中那样写呢?

例如:void (*pfunc)(void);

英文:

I was learning about pointers in Go. And managed to write something like:

func hello(){

       fmt.Println("Hello World")
}

func main(){

       pfunc := hello     //pfunc is a pointer to the function "hello"
       pfunc()            //calling pfunc prints "Hello World" similar to hello function
}

Is there a way to declare the function pointer without defining it as done above?
Can we write something like we do in C?

e.g. void (*pfunc)(void);

答案1

得分: 91

如果您使用签名,它就能工作。没有指针。

type HelloFunc func(string)

func SayHello(to string) {
    fmt.Printf("你好,%s!\n", to)
}

func main() {
    var hf HelloFunc

    hf = SayHello

    hf("世界")
}

或者您可以直接使用函数签名,而不需要声明一个新类型。

英文:

It works if you're using the signature. There's no pointer.

type HelloFunc func(string)

func SayHello(to string) {
    fmt.Printf("Hello, %s!\n", to)
}

func main() {
    var hf HelloFunc

    hf = SayHello

    hf("world")
}

Alternatively you can use the function signature directly, without declaring a new type.

答案2

得分: 36

Go语言的函数指针语法与C和C++不同。关于这一点,在Go博客上有一个很好的解释。可以理解的是,Go的作者认为C语言中的函数指针语法与普通指针太相似,因此他们决定使函数指针更加明确和可读。

下面是我写的一个示例。请注意,在calculate()函数中定义了fp参数,下面的另一个示例展示了如何将函数指针转换为类型并在函数中使用它(被注释的calculate函数)。

package main

import "fmt"

type ArithOp func(int, int) int

func main() {
    calculate(Plus)
    calculate(Minus)
    calculate(Multiply)
}

func calculate(fp func(int, int) int) {
    ans := fp(3, 2)
    fmt.Printf("\n%v\n", ans) 
}

// 这是相同的函数,但使用了上面定义的类型/fp
// 
// func calculate(fp ArithOp) {
//     ans := fp(3, 2)
//     fmt.Printf("\n%v\n", ans) 
// }

func Plus(a, b int) int {
    return a + b
}

func Minus(a, b int) int {
    return a - b
}

func Multiply(a, b int) int {
    return a * b
}

fp参数被定义为一个接受两个整数并返回一个整数的函数。这与Mue提到的内容有些相似,但展示了不同的用法示例。

英文:

Go doesn't have the same syntax for function pointers as C and C++ do. There's a pretty good explanation for that on the Go blog. Understandably the Go authors thought C's syntax for function pointers too similar to regular pointers, so in short they decided to make function pointers explicit; i.e. more readable.

Here's an example I wrote. Notice how the fp parameter is defined in calculate() and the other example below that shows you how you can make a function pointer into a type and use it in a function (the commented calculate function).

package main

import "fmt"

type ArithOp func(int, int)int

func main() {
	calculate(Plus)
	calculate(Minus)
	calculate(Multiply)
}

func calculate(fp func(int, int)int) {
	ans := fp(3,2)
	fmt.Printf("\n%v\n", ans) 
}

// This is the same function but uses the type/fp defined above
// 
// func calculate (fp ArithOp) {
//     ans := fp(3,2)
//     fmt.Printf("\n%v\n", ans) 
// }

func Plus(a, b int) int {
	return a + b
}

func Minus(a, b int) int {
	return a - b
}

func Multiply(a,b int) int {
	return a * b
}

The fp parameter is defined as a function that takes two ints and returns a single int. This is somewhat the same thing Mue mentioned but shows a different usage example.

答案3

得分: 12

一个函数在Go语言中也是一种类型。因此,你可以创建一个类型为func签名的变量。所以以下代码是有效的:

var pfunc func(string)

这个变量可以指向任何以字符串为参数并且不返回任何值的函数。以下代码段可以正常工作。

package main

import "fmt"

func SayHello(to string) {
    fmt.Printf("Hello, %s!\n", to)
}

func main() {
    var pfunc func(string)

    pfunc = SayHello

    pfunc("world")
}
英文:

A function is also a type in Go. So you can essentially create a variable of type func signature. So following would work;

var pfunc func(string)

This variable can point to any function that take string as argument and returns nothing. Following piece of code works well.

package main

import "fmt"

func SayHello(to string) {
	fmt.Printf("Hello, %s!\n", to)
}

func main() {
	var pfunc func(string)

	pfunc = SayHello

	pfunc("world")
}

答案4

得分: 5

你可以这样做:

package main

import "fmt"

func hello(){

       fmt.Println("你好,世界")
}

func main(){
       var pfunc func()
       pfunc = hello     //pfunc是指向函数"hello"的指针
       pfunc()            
}

如果你的函数有参数和返回值,它会像这样:

func hello(name string) int{

       fmt.Println("你好,%s", name)
       return 0
}

变量会像这样:

  var pfunc func(string)int
英文:

You could do it like this:

package main

import "fmt"

func hello(){

       fmt.Println("Hello World")
}

func main(){
       var pfunc func()
       pfunc = hello     //pfunc is a pointer to the function "hello"
       pfunc()            
}

If your function has arguments and e.g. a return value, it would look like:

func hello(name string) int{

       fmt.Println("Hello %s", name)
       return 0
}

and the variable would look like:

  var pfunc func(string)int

答案5

得分: 1

基于数组的函数指针解决方案

package main

import (
	"fmt"
)

type pfunc func(string, int) int

func testCase1(toStr string, toInt int) int {
	fmt.Printf("第一个函数调用 %s %d\n", toStr, toInt)
	return toInt
}

func testCase2(toStr string, toInt int) int {
	fmt.Printf("第二个函数调用 %s %d\n", toStr, toInt)
	return toInt
}

func testCase3(toStr string, toInt int) int {
	fmt.Printf("第三个函数调用 %s %d\n", toStr, toInt)
	return toInt
}

func main() {

	funcArray := []pfunc{testCase1, testCase2, testCase3}

	for n := range funcArray {
		result := funcArray[n]("测试", n)
		fmt.Printf("运行测试用例 #%d 参考 %v 结果 %d\n", n, funcArray[n], result)
	}
}
英文:

Array based function pointer solution

package main

import (
	"fmt"
)

type pfunc func(string, int)int

func testCase1(toStr string, toInt int)int {
	fmt.Printf("1st Function Call %s %d\n",toStr, toInt)
	return toInt
}

func testCase2(toStr string, toInt int)int {
	fmt.Printf("2nd Function Call %s %d\n",toStr, toInt)
	return toInt
}

func testCase3(toStr string, toInt int)int {
	fmt.Printf("3rd Function Call %s %d\n",toStr, toInt)
	return toInt
}

func main() {
		
	funcArray := []pfunc{testCase1,testCase2,testCase3}	
	
	for n:=range funcArray {
		result := funcArray[n]("Test", n)
		fmt.Printf("Run Test Case #%d reference %v result %d\n",n, funcArray[n], result)
	}
}

答案6

得分: 0

另一种方法是定义一个接口

type command interface {
      DoLoop()
}

实现一个实现该接口的结构体

type Delete struct {
      instance string
}

func (dev Delete) DoLoop() {
      fmt.Println("输入:删除")
}

创建包含该结构体的映射

mainFuncTable = make(map[string]command)
mainFuncTable["delete"] = Delete{"new"}

然后调用函数

func route(command string) {
      cmd := mainFuncTable[command]
      cmd.DoLoop()
}

这种方法有点间接,但是它可以工作。

英文:

A different way to approach it is to define an interface

type command interface {
      DoLoop()
}

implement a struct that implements it

type Delete struct {
      instance string
}

func (dev Delete) DoLoop() {
      fmt.Println("input: delete ")
}

Create map that contains the struct

 mainFuncTable = make(map[string]command)
 mainFuncTable["delete"] = Delete{"new"}

the call the function

func route(command string) {
      cmd := mainFuncTable[command]
      cmd.DoLoop()
}

It's a little indirect but it works

答案7

得分: 0

我参考了C语言中的函数指针和JavaScript中的回调函数。

在C语言中,我们使用函数指针将函数作为参数传递给另一个函数,因为函数指针可以像变量一样使用。

#include <stdio.h>

int add(int x, int y) {
    return x + y;
}

int sub(int x, int y) {
    return x - y;
}

int calc(int (*fp)(int, int), int a, int b) {
    return (*fp)(a, b);
}

int main() {
   
    printf("%d\n", calc(add, 5, 6)); // 11  
    printf("%d\n", calc(sub, 9, 6)); // 3
    
    return 0;
}

在JavaScript中,我们可以直接将函数作为参数传递。

/* JavaScript Code Snippet */
var foo = function() {
    alert("Foo");
}

function bar(f) {
    f();
}

bar(foo)

我尝试在Go中复制相同的场景。
在这里,calc函数的使用者不需要关心add函数的内部实现。

使用者只需要知道他/她需要执行的功能,然后将函数名作为参数传递给calc函数。

package main
import "fmt"

func add(x, y int) int {
    return x + y;
}

func sub(x, y int) int {
    return x - y;
}

func calc(fp func(int, int) int, x, y int) {
    fmt.Println(fp(x, y));
}

func main() {
    calc(add, 5, 6); // 11
    calc(sub, 7, 4); // 3

    calc(func(x, y int) int{
        return x * y;
    }, 5, 3); //这将打印出15
}

如果需要,我们还可以创建匿名函数,就像我们为乘法创建的那样。

如果你想直接使用函数指针,下面的代码片段可以工作。

package main
import "fmt"

func greet(){
    fmt.Println("Hello World")
}

func main() {

    fptr := greet
    fmt.Println(fptr) //这将打印出地址
    fptr()
}

希望这可以帮到你。

英文:

I have taken reference from function pointer in c language and callback function from JavaScript

In c language we use function pointer to pass function as an argument to another function as function pointer act as a variable.

#include &lt;stdio.h&gt;

int add(int x, int y) {
    return x + y;
}

int sub(int x, int y) {
    return x - y;
}

int calc(int (*fp)(int, int), int a, int b) {
    return (*fp)(a, b);
}

int main() {
   
    printf(&quot;%d\n&quot;, calc(add, 5, 6)); // 11  
    printf(&quot;%d\n&quot;, calc(sub, 9, 6)); // 3
    
    return 0;
}

In JavaScript we can directly pass function as an argument

/* JavaScript Code Snippet */
var foo = function() {
    alert(&quot;Foo&quot;);
}

function bar(f) {
    f();
}

bar(foo)

I tried to replicate same scenario in Go
Here the user of cacl function doesn't need to worry about what is inside the add function

The user just need to know what functionality he/she needs to perform based on which he/she pass function name as argument to calc function

package main
import &quot;fmt&quot;

func add(x, y int) int {
    return x + y;
}

func sub(x, y int) int {
    return x - y;
}

func calc(fp func(int, int) int, x, y int) {
    fmt.Println(fp(x, y));
}

func main() {
    calc(add, 5, 6); // 11
    calc(sub, 7, 4); // 3

    calc(func(x, y int) int{
        return x * y;
    }, 5, 3); //this will print 15

}

Also if required we can create anonymous function like we created for multiplication

And if you want to use pointer to function directly then following snippet would work

package main
import &quot;fmt&quot;

func greet(){
    fmt.Println(&quot;Hello World&quot;)
}

func main() {

    fptr := greet
    fmt.Println(fptr) //this will print address
    fptr()
}

I hope this will help.

huangapple
  • 本文由 发表于 2010年8月30日 23:24:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/3601796.html
匿名

发表评论

匿名网友

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

确定