2012-02-22 92 views
7

我想创建特定类型的函数。我找到了一种方法来做到这一点,但必须有其他更清洁更好的方法,不包括使用varGreeting类型的函数english有哪些替代方法?在Go中使用函数类型

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

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

+2

由于您将'english'声明为全局变量,因此不能删除'var'。 – Mostafa 2012-02-22 21:29:23

回答

12

如果提var是你的主要问题,你可以轻松地删除它,通过改变=:=,像这样:

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

但是,你甚至不必投你的函数为Greeting。规范说这是关于function types

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

而这大约type identity

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

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

所以,下面的代码工作,我希望显示围棋与函数类型工作的正确方法:

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功能。如果他们不需要,开发人员不要使用这些标点符号。

UPDATE:既然您已经提供了示例代码,我可以清楚地理解问题。

为此,您的代码已经足够好了,而且没有太多的其他方法可以做到这一点。如果你喜欢,你可以在调用方法之前施放:

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显示编码同一件事的两种不同的方式。再说一遍,我并不是说这是更好的解决方案,而是更常见和更灵活的达到同样效果的方式。

+1

感谢您的回答。但我的问题是如何声明特定类型的函数。在你的代码示例中,你永远不会这样做。我已经更新了我的示例,正​​如您可能注意到的那样,当您为该类型添加方法时,除非执行'Greeting(func(name string)...)部分,否则无法访问它。 – ANisus 2012-02-22 19:33:41

+0

我也明白为什么你可能已经改变了标题,假设具有相同参数和结果类型的两个函数是相同的。然而,当使用类型方法时,情况并非如此。然后'func english(...)'和'Greeting(func english(...))'将会有所不同。一个可能不会访问类型方法。所以,我认为第一个标题更正确。 – ANisus 2012-02-22 19:49:07

+0

啊,谢谢你的更新!你的回答肯定帮助我更好地理解它。当我遇到'websocket.Handler'时,我开始试用它,它是一个函数类型,使用方法ServeHTTP(w http.ResponseWriter,req * http.Request)(实现'http.Handler'接口)。再次感谢! – ANisus 2012-02-23 07:57:16

3

想在这里不同的问题,

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

是声明函数类型的英语问候的方式。注意问候语不用于英语的定义,因此这可能不符合您声明特定类型功能的要求。否则,对不起,Go没有办法定义一个特定的(即单独定义的)类型的函数。这可能是很好的类型的东西,如

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

但没有,在Go没有办法。英语的声明不能使用问候语,并且必须重复功能签名。取而代之的是,只有在作业中才能使用英语为Greeting的要求

g = english 

g被声明为Greeting类型。如果英文不是同一类型,则该行不会编译。

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

+1

我是那种寻找你用'english:=问候语{...}行说明你在哪里解释说有没有这样的方式。但是你已经让我进一步了解如何以Go惯用方式处理函数类型。 – ANisus 2012-03-08 14:33:55