Estoy aprendiendo Go escribiendo una aplicación para GAE, y esta es la firma de una función de controlador:
func handle(w http.ResponseWriter, r *http.Request) {}
Soy un novato de puntero aquí, entonces, ¿por qué el Request
objeto es un puntero, pero ResponseWriter
no? ¿Es necesario hacerlo de esta manera o es solo para hacer posible algún tipo de código avanzado basado en punteros?
Como se mencionó correctamente en muchas otras respuestas aquí y en otros lugares,
ResponseWriter
es una interfaz y las implicaciones de esto se han descrito en detalle en las respuestas y blogs de SO .Lo que me gustaría abordar es lo que creo que es el gran y peligroso concepto erróneo aquí, de que la razón por la que la solicitud se pasa por "referencia" (aunque tal cosa realmente no existe en Go ) es que "queremos hacer cambios para que sea visible para el servidor ".
Citando un par de respuestas:
Esto está mal ; de hecho, los documentos advierten explícitamente contra la manipulación / mutación de la solicitud :
Todo lo contrario, ¿no? :-)
Si desea cambiar la solicitud, por ejemplo, agregar un encabezado de seguimiento antes de pasarlo al siguiente controlador en una cadena de middleware, debe copiar la solicitud y pasar la versión copiada en la cadena.
Las solicitudes para cambiar el comportamiento para permitir modificaciones de la solicitud entrante se han planteado con el equipo Go pero cambiando algo como esto probablemente daría lugar a por lo menos algo de código existente romper inesperadamente.
¿Por qué usar un puntero si le decimos explícitamente a las personas que no modifiquen la solicitud? El rendimiento ,
Request
es una gran estructura y la copia que puede aportar el rendimiento abajo, especialmente con cadenas largas de middleware en mente. El equipo tuvo que encontrar un equilibrio, definitivamente no es una solución ideal, pero las compensaciones están claramente del lado del rendimiento aquí (en lugar de la seguridad de la API).fuente
La razón por la que es un puntero a Solicitud es simple: los cambios a Solicitud por parte del controlador deben ser visibles para el servidor, por lo que solo lo pasamos por referencia en lugar de por valor.
Si profundiza en el código de la biblioteca net / http, encontrará que ResponseWriter es una interfaz para una respuesta de estructura no exportada, y estamos pasando la estructura por referencia (estamos pasando un puntero a la respuesta) y no por valor . ResponseWriter es una interfaz que utiliza un controlador para crear una respuesta HTTP. La estructura real que respalda ResponseWriter es la estructura http.response no exportada. Debido a que no se exporta, no puede usarlo directamente; solo puede usarlo a través de la interfaz ResponseWriter.
En otras palabras, ambos parámetros se pasan por referencia; es solo que la firma del método toma un ResponseWriter que es una interfaz a un puntero a una estructura, por lo que parece que se pasa por valor.
fuente
Creo que la razón principal por la que el
Request
objeto se pasa como puntero es elBody
campo. Para una solicitud HTTP determinada, el cuerpo solo se puede leer una vez. Si elRequest
objeto fue clonado, como sería si no se pasara como puntero, tendríamos dos objetos con información diferente sobre cuánto se ha leído del cuerpo.fuente