在Go中使用函数类型

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

Working with function types in Go

问题

我想创建一个特定类型的函数。我找到了一种方法来实现,但肯定还有其他更简洁和更好的方法,不需要使用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,因为那样我将无法访问exclamation方法。

英文:

I wanted to create a function of a certain type. I've found one way to do it, but there must be other, cleaner and nicer ways that do not include using var. What are the alternative ways to declare the function english of type Greeting?

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"))	
}

In the example above, I can't exchange var english = Greeting... with english := Greeting..., nor can I remove the Greeting(func ...) and just have the func stand alone since then I won't be able to access the exclamation method.

答案1

得分: 47

如果提到var是你的主要问题,你可以很容易地将其删除,只需将=改为:=,像这样:

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

但是你甚至不需要将函数转换为Greeting类型。规范对函数类型有如下说明:

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

对于类型标识,规范有如下说明:

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

这意味着每个函数都有自己的函数类型。如果两个函数具有相同的签名(参数和结果类型),它们共享一个函数类型。通过编写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展示了两种不同的编码方式。再次强调,我并不是说这是更好的解决方案,而是一种更常见和更灵活的实现相同效果的方式。

英文:

If mentioning var is your main problem, you can drop it easily, by changing = into :=, like this:

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

But you don't even have to cast your function into Greeting. The spec says this about function types:

> A function type denotes the set of all functions with the same parameter and result types.

And this about type identity:

> Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.

This means that each function has its own function type. If two functions have the same signature (parameter and result types), they share one function type. By writing type Greeting func... you're just giving a name to a particular function type, not defining a new one.

So the following code works, and I hope shows the right way to work with function types in 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")
}

Notice that I also dropped semicolon and parenthesis from your english function. Go developers don't use these punctuations if they don't have to.

UPDATE: Now that you've provided a sample code I can clearly understand the problem.

For this purpose your code is good enough and there are not much other ways of doing it. If you like you can cast just before calling the method:

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

But I'm not sure this is an improvement. I'm just saying that for what you want to do there does not seem to be other ways to write the code.

That is, if we don't want to change your types. I mean, the whole idea of calling a method on a function type seems a little weird. Not that it's wrong, but a little rare. Another way of achieving the same effect in a more usual way is through a struct type and having a field for the function. Something like this:

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"))
}

Here english and french show two different ways of coding the same thing. Again, I'm not saying that this is the better solution, but a more usual and more flexible way of achieving the same effect.

答案2

得分: 11

尝试在这里分离问题,

type Greeting func(string) string

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

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

这是声明函数english为类型Greeting的方式。请注意,在english的定义中没有使用Greeting,因此这可能不符合您声明特定类型函数的要求。否则,很抱歉,在Go中没有办法定义特定类型(即单独定义的)的函数。可能会希望像这样输入一些内容:

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

但是,很抱歉,在Go中没有办法。english的声明不能使用Greeting,并且必须重复函数签名。相反,只有在赋值中才要求english是Greeting类型的:

g = english

g被声明为类型Greeting。如果english不是相同类型,该行将无法编译。

除了重复类型签名的问题之外,例如方法的问题,如果您仍然在寻找其他组织示例功能的方法,那么目前还不清楚。当然可以用其他方式完成。一个更大的示例,可能作为一个单独的问题提出,会有所帮助。

英文:

Trying to separate issues here,

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"))
}

Is the way to declare the function english of type Greeting. Notice Greeting is not used in the definition of english, so this may not meet your requirement of declaring a function of a specific type. Otherwise, sorry, there is no way in Go to define a function of a specific (that is, separately defined) type. It might be nice to type something like,

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

but no, there is no way in Go. The declaration of english can't use Greeting, and must repeat the function signature. Instead the requirement that english is of type Greeting is made only in the assignment

g = english

g is declared of type Greeting. If english isn't the same type, the line won't compile.

Beyond the issue of repeating the type signature--the issues of methods, for example--it's not clear if you're still looking for other ways to organize the functionality of your example. It can certainly be done other ways. A bigger example though, maybe posed as a separate question, would help.

huangapple
  • 本文由 发表于 2012年2月23日 00:22:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/9398739.html
匿名

发表评论

匿名网友

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

确定