pointers - ingles - qué significa en español
Tipos de métodos de estructura de Go que satisfacen una interfaz (2)
Dado el siguiente ejemplo de código Go:
package main
import "fmt"
type greeter interface {
hello()
goodbye()
}
type tourGuide struct {
name string
}
func (t tourGuide) hello() {
fmt.Println("Hello", t.name)
}
func (t *tourGuide) goodbye() {
fmt.Println("Goodbye", t.name)
}
func main() {
var t1 tourGuide = tourGuide{"James"}
t1.hello() // Hello James
t1.goodbye() // Goodbye James (same as (&t1).goodbye())
var t2 *tourGuide = &tourGuide{"Smith"}
t2.hello() // Hello Smith
t2.goodbye() // Goodbye Smith (same as (*t2).hello())
// illegal: t1 is not assignable to g1 (why?)
// var g1 greeter = t1
var g2 greeter = t2
g2.hello() // Hello Smith
g2.goodbye() // Goodbye Smith
}
Puedo llamar a los dos métodos de struct tourGuide
utilizando una variable de tipo tourGuide t1
o un puntero a tourGuide t2
. En otras palabras, puedo llamar a un método con receptor T
utilizando una variable de tipo T
o *T
De manera similar, puedo llamar a un método con un receptor *T
usando una variable de tipo T
(si T
es direccionable ) o *T
Entiendo que el compilador maneja las diferencias aquí (ver mis comentarios en el código).
Sin embargo, las cosas cambian cuando estamos implementando interfaces. En el código anterior, una variable de la greeter
de tipo greeter
se puede tourGuide
desde un puntero a tourGuide
pero no desde un tourGuide
.
¿Alguien puede decirme por qué este es el caso? ¿Por qué puedo llamar a t1.hello()
y t1.goodbye()
pero de alguna manera t1
no es suficiente para la interfaz de greeter
?
si tiene un puntero a una estructura, entonces ir le permitirá acceder a las propiedades de la estructura y sus funciones que tienen receptores de tipo de valor (como los receptores de punteros) sin tener que desreferenciar su puntero, pero esto solo funciona para un nivel de puntero, vea su código a continuación, donde convierto t2 en un puntero a un puntero a un tourguide
, en este punto necesito desreferencia explícitamente para volver a convertirlo en un puntero a un tourguide
. piense que el primer nivel de un puntero a una estructura es un caso especial que le permite usar azúcar sintáctica para acceder a las propiedades y funciones de los tipos de valores para ahorrarle tener que desreferenciar constantemente sus variables constantemente.
package main
import "fmt"
type greeter interface {
hello()
goodbye()
}
type tourGuide struct {
name string
}
func (t tourGuide) hello() {
fmt.Println("Hello", t.name)
}
func (t *tourGuide) goodbye() {
fmt.Println("Goodbye", t.name)
}
func main() {
var t1 tourGuide = tourGuide{"James"}
t1.hello() // Hello James
t1.goodbye() // Goodbye James (same as (&t1).goodbye())
var tmpT2 *tourGuide = &tourGuide{"Smith"}
var t2 **tourGuide = &tmpT2
(*t2).hello() // Hello Smith
(*t2).goodbye() // Goodbye Smith (same as (*t2).hello())
//illegal: t1 is not assignable to g1 (why?)
//var g1 greeter = t1
//now this is illegal too
//var g2 greeter = t2
var g3 greeter = (*t2)
g3.hello() // Hello Smith
g3.goodbye() // Goodbye Smith
}
Si un método tiene un receptor de puntero, solo se puede usar un valor de puntero como valor de receptor. Entonces, para llamar a este método con algún valor, el valor en sí mismo debe ser un puntero, o debe ser posible adquirir su dirección (para ser utilizado como el receptor).
Si tiene una variable, por ejemplo, es direccionable y, por lo tanto, es posible obtener su dirección y usarla como receptor. Y la especificación le permite hacer esto, esto sucede automáticamente.
Los valores envueltos en interfaces no son direccionables. Cuando se crea un valor de interfaz, se copia el valor que está envuelto en la interfaz. Por lo tanto, no es posible tomar su dirección. Teóricamente, podría permitir tomar la dirección de la copia, pero esa sería la fuente de (incluso) más confusión que el beneficio que proporcionaría, ya que la dirección apuntaría a una copia, y los métodos con el receptor de puntero solo podrían modificar la copia. y no el original.
Vea esta respuesta que detalla / demuestra que los valores se copian cuando se crea el valor de la interfaz: ¿Cómo puede contener una porción?