2012-02-22 3 views
7

Я хотел создать функцию определенного типа. Я нашел один способ сделать это, но должны быть другие, более чистые и более приятные способы, которые не включают использование var. Каковы альтернативные способы объявления функции english типа Greeting?Работа с типами функций в 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")) 
} 

В приведенном выше примере, я не могу обменять var english = Greeting... с english := Greeting..., и я не могу удалить Greeting(func ...) и просто иметь func стоять в одиночестве с тех пор я не смогу получить доступ к восклицательному методу.

+2

Вы не можете удалить 'var', потому что вы объявляете' english' как глобальную переменную. – Mostafa

ответ

12

Если упоминая var ваша главная проблема, вы можете оставить его легко, изменив = в :=, как это:

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

Но вы даже не должны отбрасывать вашу функцию в Greeting. Спектр говорит об этом function types:

Тип функции обозначает набор всех функций с теми же параметрами и типами результатов.

И это о type identity:

Два типа функций идентичны, если они имеют одинаковое количество параметров и значений результатов, соответствующие параметры и результаты типов идентичны, и либо обе функции VARIADIC или ни является. Имена параметров и результатов не обязательно совпадают.

Это означает, что каждая функция имеет свой собственный тип функции. Если две функции имеют одну и ту же подпись (параметры и типы результатов), они имеют один тип функции. Написав 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 функции. Разработчики не используют эти пунктуации, если им это не нужно.

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

Здесь english и french показывают два различных способа кодирования то же самое. Опять же, я не говорю, что это лучшее решение, но более обычный и более гибкий способ достижения такого же эффекта.

+1

Спасибо за ответ. Но мой вопрос заключался в том, как объявить функцию определенного типа. В вашем примере кода вы никогда этого не делаете. Я обновил свой пример, и, как вы могли заметить, при добавлении метода к типу вы не можете получить к нему доступ, если не используете часть «Приветствие (func (name string) ...). – ANisus

+0

Я также понимаю, почему вы, возможно, изменили название, из предположения, что две функции с одинаковыми параметрами и типами результатов идентичны. Однако это не так, если вы работаете с методами типа. Тогда 'func english (...)' и 'Greeting (func english (...))' будет другим. Невозможно получить доступ к методу типа, в то время как другой может. Итак, я думаю, что первое название было более правильным. – ANisus

+0

А, спасибо за обновление! Ваш ответ, несомненно, помог мне понять это лучше. Я начал опробовать его, когда я столкнулся с 'websocket.Handler', который является типом функции с помощью метода ServeHTTP (w http.ResponseWriter, req * http.Request)' (реализация интерфейса http.Handler). Еще раз спасибо! – ANisus

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 нет никакого способа. Объявление по-английски не может использовать Приветствие и должно повторять подпись функции. Вместо того, чтобы требование, что английский имеет тип приветствие производится только в назначении

g = english 

г объявляется тип приветствия. Если английский не тот же тип, строка не будет компилироваться.

Помимо проблемы повторения подписи типа - например, проблемы методов - неясно, если вы все еще ищете другие способы организации функциональности вашего примера. Это, безусловно, можно сделать другими способами. Больший пример, возможно, может быть поставлен как отдельный вопрос, поможет.

+1

Я искал то, что вы проиллюстрировали с помощью строки 'english: = Greeting {...}', где вы объяснили, что есть нет такого пути. Но вы заставили меня понять, как работать с типами функций в идиоматическом режиме Go. – ANisus

Смежные вопросы