2012-02-22 9 views
7

Quería crear una función de cierto tipo. He encontrado una forma de hacerlo, pero debe haber otras formas más limpias y agradables que no incluyan el uso de var. ¿Cuáles son las formas alternativas de declarar la función english del tipo Greeting?Trabajando con tipos de funciones en 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")) 
} 

En el ejemplo anterior, no puedo intercambiar con var english = Greeting...english := Greeting..., ni puedo quitar el Greeting(func ...) y sólo tienen el func stand alone desde entonces no voy a ser capaz de acceder al métodoexclamación.

+2

No puede eliminar 'var' porque está declarando' english' como una variable global. – Mostafa

Respuesta

12

Si var mencionar es su principal problema, se puede eliminar fácilmente, cambiando = en :=, así:

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

Pero no siquiera tiene que emitir su función en Greeting. La especificación dice esto sobre function types:

Un tipo de función denota el conjunto de todas las funciones con el mismo parámetro y los mismos tipos de resultados.

Y esto sobre type identity:

dos tipos de función son iguales si tienen el mismo número de parámetros y valores de resultado, tipos de parámetro y de resultados correspondiente son idénticos, y, o bien ambas funciones son variadic o ninguno es. No es necesario que coincidan los nombres de parámetros y resultados.

Esto significa que cada función tiene su propio tipo de función. Si dos funciones tienen la misma firma (tipos de parámetros y resultados), comparten un tipo de función. Al escribir type Greeting func... solo está dando un nombre a un tipo de función en particular, sin definir uno nuevo.

Así que el siguiente código funciona, y espero que muestra la manera correcta de trabajar con tipos de funciones de movimiento:

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

Tenga en cuenta que también cayó punto y coma y paréntesis de su función english. Los desarrolladores de Go no usan estas puntuaciones si no es necesario.

ACTUALIZACIÓN: Ahora que ha proporcionado un código de muestra, puedo entender claramente el problema.

Para este propósito, su código es lo suficientemente bueno y no hay muchas otras formas de hacerlo. Si lo desea, puede lanzar antes de llamar al método:

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

Pero no estoy seguro de que esto sea una mejora. Solo digo que por lo que quieres hacer no parece haber otras formas de escribir el código.

Es decir, si no queremos cambiar sus tipos. Quiero decir, la idea de llamar a un método en un tipo de función parece un poco extraño. No es que esté mal, pero es un poco raro. Otra forma de lograr el mismo efecto de una manera más habitual es mediante un tipo de estructura y un campo para la función.Algo como esto:

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

Aquí english y french muestran dos formas diferentes de codificación de la misma cosa. Una vez más, no estoy diciendo que esta sea la mejor solución, sino una forma más habitual y más flexible de lograr el mismo efecto.

+1

Gracias por la respuesta. Pero mi pregunta era cómo declarar una función de un tipo específico. En tu ejemplo de código, nunca haces eso. He actualizado mi ejemplo y, como puede observar, cuando agrega un método al tipo, no puede acceder a él a menos que haga la parte 'Saludo (func (cadena de caracteres) ...). – ANisus

+0

También entiendo por qué podría haber cambiado el título, partiendo de la suposición de que dos funciones con los mismos parámetros y tipos de resultados son idénticas. Sin embargo, este no es el caso cuando se trabaja con métodos tipo. Entonces 'func english (...)' y 'Greeting (func english (...))' serán diferentes. Uno no puede acceder al método de tipo mientras que el otro puede. Entonces, creo que el primer título fue más correcto. – ANisus

+0

¡Ah, gracias por la actualización! Tu respuesta seguramente me ayudó a entenderlo mejor. Empecé a probarlo cuando me encontré con 'websocket.Handler' que es un tipo de función con el método' ServeHTTP (w http.ResponseWriter, req * http.Request) '(implementa la interfaz' http.Handler'). ¡Gracias de nuevo! – ANisus

3

Tratando de separar las cuestiones aquí,

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

es la manera de declarar la función del Inglés tipo de saludo. Aviso El saludo no se usa en la definición de inglés, por lo que puede no cumplir con su requisito de declarar una función de un tipo específico. De lo contrario, lo siento, no hay forma de que vaya a definir una función de un tipo específico (es decir, definido por separado). Podría ser agradable escribir algo como,

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

pero no, no hay forma de ir. La declaración de inglés no puede usar Saludo, y debe repetir la firma de la función. En lugar de ello el requisito de que Inglés es de tipo de saludo se hace sólo en la asignación

g = english 

g se declara de tipo de saludo. Si el inglés no es del mismo tipo, la línea no se compilará.

Más allá del problema de repetir la firma del tipo, por ejemplo, los problemas de los métodos, no está claro si aún está buscando otras formas de organizar la funcionalidad de su ejemplo. Sin duda se puede hacer de otras maneras. Sin embargo, un ejemplo más grande, tal vez planteado como una pregunta separada, ayudaría.

+1

Estaba buscando lo que ilustraste con la línea 'english: = Greeting {...}', donde explicaste que hay no de esa manera. Pero me has hecho entender mejor cómo trabajar con tipos de funciones de una manera idiomática. – ANisus

Cuestiones relacionadas