Работа с типами функций в Go - PullRequest
12 голосов
/ 22 февраля 2012

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

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

Ответы [ 2 ]

21 голосов
/ 22 февраля 2012

Если упоминание 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"))
}

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

6 голосов
/ 07 марта 2012

Попытка разделить вопросы здесь,

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

Это способ объявления функции english типа Greeting.Уведомление Приветствие не используется в определении английского языка, поэтому оно может не соответствовать вашему требованию объявления функции определенного типа.В противном случае, извините, в Go нет способа определить функцию определенного (то есть отдельно определенного) типа.Было бы неплохо напечатать что-то вроде

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

, но нет, в Go нет пути.Объявление английского языка не может использовать Greeting и должно повторять сигнатуру функции.Вместо этого требование о том, что английский имеет тип Greeting, выполняется только в присваивании

g = english

g типа Greeting.Если английский не тот же тип, строка не скомпилируется.

Помимо проблемы повторения сигнатуры типа - например, проблем с методами - не ясно, продолжаете ли вы искатьдля других способов организовать функционал вашего примера.Конечно, это можно сделать другими способами.Однако поможет более крупный пример, который может быть задан как отдельный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...