2012-02-22 81 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