【问题标题】:Working with function types in Go在 Go 中使用函数类型
【发布时间】:2012-03-13 00:19:37
【问题描述】:

我想创建一个特定类型的函数。我找到了一种方法来做到这一点,但必须有其他更清洁和更好的方法,不包括使用var。声明 Greeting 类型的函数 english 的替代方法是什么?

package main

import "fmt"

type Greeting func(name string) string

func (g Greeting) exclamation(name string) string {
    return g(name) + "!"
}

var english = Greeting(func(name string) string {
    return "Hello, " + name
})

func main() {
    fmt.Println(english("ANisus"))
    fmt.Println(english.exclamation("ANisus"))  
}

在上面的示例中,我不能将var english = Greeting...english := Greeting... 交换,也不能删除Greeting(func ...) 并让func 独立,从那时起我将无法访问感叹号方法。

【问题讨论】:

  • 您无法删除 var,因为您将 english 声明为全局变量。

标签: function types go


【解决方案1】:

如果提到var 是您的主要问题,您可以轻松地将其删除,方法是将= 更改为:=,如下所示:

english := Greeting(func(name string) string {
    return ("Hello, " + name);
})

但您甚至不必将函数转换为 Greeting。规范中提到了function types

函数类型表示具有相同参数和结果类型的所有函数的集合。

关于type identity

如果两个函数类型相同,如果它们具有相同数量的参数和结果值,对应的参数和结果类型相同,并且两个函数都是可变的,或者两者都不是。参数和结果名称不需要匹配。

这意味着每个函数都有自己的函数类型。如果两个函数具有相同的签名(参数和结果类型),则它们共享一种函数类型。通过编写type Greeting func...,您只是为特定函数类型命名,而不是定义新函数类型。

所以下面的代码可以工作,我希望能展示在 Go 中使用函数类型的正确方法:

package main

import "fmt"

type Greeting func(name string) string

func say(g Greeting, n string) { fmt.Println(g(n)) }

func french(name string) string { return "Bonjour, " + name }

func main() {
        english := func(name string) string { return "Hello, " + name }

        say(english, "ANisus")
        say(french, "ANisus")
}

请注意,我还从您的 english 函数中删除了分号和括号。如果非必要,Go 开发人员不会使用这些标点符号。

更新:现在您已经提供了示例代码,我可以清楚地理解问题所在。

为此,您的代码已经足够好,没有太多其他方法可以做到这一点。如果您愿意,可以在调用该方法之前进行转换:

english := func(name string) string { return "Hello, " + name }
Greeting(english).exclamation("ANisus")

但我不确定这是一种改进。我只是说,对于您想做的事情,似乎没有其他方法可以编写代码。

也就是说,如果我们不想更改您的类型。我的意思是,在函数类型上调用方法的整个想法似乎有点奇怪。不是说错了,而是有点少见。以更常见的方式实现相同效果的另一种方法是通过结构类型并为函数提供一个字段。像这样的:

package main

import "fmt"

type Greeting struct {
    say func(name string) string
}

func newGreeting(f func(string) string) *Greeting {
    return &Greeting{say: f}
}

func (g *Greeting) exclamation(name string) string { return g.say(name) + "!" }

func main() {
    english := &Greeting{say: func(name string) string {
        return "Hello, " + name
    }}

    french := newGreeting(func(name string) string {
        return "Bonjour, " + name
    })

    fmt.Println(english.exclamation("ANisus"))
    fmt.Println(french.exclamation("ANisus"))
}

这里englishfrench 显示了编码同一事物的两种不同方式。同样,我并不是说这是更好的解决方案,而是一种更常用、更灵活的方式来实现相同的效果。

【讨论】:

  • 感谢您的回答。但我的问题是如何声明特定类型的函数。在您的代码示例中,您永远不会这样做。我已经更新了我的示例,您可能会注意到,当您向类型添加方法时,除非您执行 `Greeting(func(name string) ...) 部分,否则您无法访问它。
  • 我也理解你为什么改变了标题,假设两个函数具有相同的参数和结果类型是相同的。然而,在使用类型方法时情况并非如此。那么func english(...)Greeting(func english(...)) 就会不同。一个可能无法访问类型方法,而另一个可能。所以,我认为第一个标题更正确。
  • 啊,感谢您的更新!您的回答肯定有助于我更好地理解它。当我遇到websocket.Handler 时开始尝试它,它是一个函数类型,方法为ServeHTTP(w http.ResponseWriter, req *http.Request)(实现http.Handler 接口)。再次感谢!
  • 如果函数类型是在其他文件中声明的,比如这种类型的 Greeting func(name string) string 然后导入该文件,我可以不使用它吗?它说,无法将 func 文字(类型 func(名称字符串)字符串)转换为类型“otherfile.Greeting”。我可以从该文件中访问所有其他内容
  • 如果要调用方法exclaimation,仍然需要转换为类型Greeting。否则它将无法工作play.golang.org/p/LJ8iVG6-gZ
【解决方案2】:

试图在这里分开问题,

type Greeting func(string) string

func english(name string) string {
    return return "Hello, " + name
}

func main() {
    var g Greeting
    g = english
    fmt.Println(g("ANisus"))
}

是Greeting类型的函数English的声明方式。注意 英文的定义中没有使用 Greeting,所以这可能不符合您声明特定类型函数的要求。否则,抱歉,Go 中无法定义特定(即单独定义)类型的函数。输入类似的内容可能会很好,

english := Greeting {
    return return "Hello, " + name
}

但是不,Go 中没有办法。英文的声明不能使用 Greeting,必须重复函数签名。相反,要求英语是问候类型的要求仅在作业中提出

g = english

g 被声明为 Greeting 类型。如果英语不是同一类型,则该行将无法编译。

除了重复类型签名的问题(例如方法问题)之外,尚不清楚您是否还在寻找其他方法来组织示例的功能。当然可以通过其他方式完成。不过,一个更大的例子(可能作为一个单独的问题提出)会有所帮助。

【讨论】:

  • 我正在寻找您在english := Greeting { ... } 行中说明的内容,您在其中解释说没有这种方法。但是您让我进一步了解了如何以 Go 惯用的方式使用函数类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 2019-04-17
  • 2017-06-22
  • 2018-02-19
  • 1970-01-01
  • 2014-05-19
  • 1970-01-01
相关资源
最近更新 更多