No está muy claro para mí en cuyo caso querría usar un receptor de valor en lugar de usar siempre un receptor de puntero.
Para recapitular de los documentos:
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
Los documentos también dicen: "Para tipos como tipos básicos, porciones y estructuras pequeñas, un receptor de valores es muy barato, por lo que, a menos que la semántica del método requiera un puntero, un receptor de valores es eficiente y claro".
El primer punto dice que es "muy barato", pero la pregunta es más si es más barato que el receptor de puntero. Así que hice un pequeño punto de referencia (código en esencia) que me mostró que el receptor de puntero es más rápido incluso para una estructura que tiene solo un campo de cadena. Estos son los resultados:
// Struct one empty string property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 500000000 3.62 ns/op
// Struct one zero int property
BenchmarkChangePointerReceiver 2000000000 0.36 ns/op
BenchmarkChangeItValueReceiver 2000000000 0.36 ns/op
(Editar: tenga en cuenta que el segundo punto dejó de ser válido en las versiones más recientes de Go, consulte los comentarios) .
Segundo punto dice, es "eficiente y claro" lo que es más una cuestión de gustos, ¿no? Personalmente, prefiero la coherencia al usarlo en todas partes de la misma manera. ¿Eficiencia en qué sentido? En cuanto al rendimiento, parece que los punteros son casi siempre más eficientes. Pocas pruebas con una propiedad int mostraron una ventaja mínima del receptor Value (rango de 0.01-0.1 ns / op)
¿Alguien puede decirme un caso en el que un receptor de valores claramente tenga más sentido que un receptor de puntero? ¿O estoy haciendo algo mal en el punto de referencia? ¿Pasé por alto otros factores?
Respuestas:
Tenga en cuenta que las preguntas frecuentes mencionan la coherencia
Como se menciona en este hilo :
Ahora:
El comentario de Revisión de código puede ayudar:
La parte en negrita se encuentra, por ejemplo, en
net/http/server.go#Write()
:fuente
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers
En realidad, no es cierto. Los métodos de receptor de valor y de receptor de puntero pueden invocarse en un puntero o no puntero correctamente escrito. Independientemente de cómo se llame al método, dentro del cuerpo del método, el identificador del receptor se refiere a un valor por copia cuando se usa un receptor de valor, y un puntero cuando se usa un receptor de puntero: Ver play.golang.org/p / 3WHGaAbURMInt(5).increment_by_one_ptr()
. Del mismo modo, un rasgo que define el métodoincrement_by_one_ptr
no se satisfará con un valor de tipoInt
.Para agregar adicionalmente a @VonC, una gran respuesta informativa.
Me sorprende que nadie haya mencionado realmente el costo de mantenimiento una vez que el proyecto crece, los desarrolladores antiguos se van y llega uno nuevo. Go seguramente es un idioma joven.
En general, trato de evitar los consejos cuando puedo, pero tienen su lugar y su belleza.
Uso punteros cuando:
P.ej:
Razones por las que evito los consejos:
Mi regla general es escribir tantos métodos encapsulados como sea posible, como:
ACTUALIZAR:
Esta pregunta me inspiró a investigar más el tema y escribir una publicación de blog al respecto https://medium.com/gophersland/gopher-vs-object-oriented-golang-4fa62b88c701
fuente