slices golang example array string http go slice

string - example - map golang



¿Cuál es la diferencia entre ResponseWriter.Write y io.WriteString? (2)

io.Writer

Un flujo de salida representa un destino en el que puede escribir la secuencia de bytes. En Go, esto se captura mediante la interfaz general de io.Writer :

type Writer interface { Write(p []byte) (n int, err error) }

Todo lo que tiene este único método Write() se puede usar como una salida, por ejemplo, un archivo en su disco ( os.File ), una conexión de red ( net.Conn ) o un búfer en memoria ( bytes.Buffer ).

El http.ResponseWriter que se usa para configurar la respuesta HTTP y enviar los datos al cliente también es un io.Writer , los datos que desea enviar (el cuerpo de la respuesta) se ensamblan llamando (no necesariamente solo una vez) ResponseWriter.Write() (que es para implementar el general io.Writer ). Esta es la única garantía que tiene sobre la implementación de la interfaz http.ResponseWriter .

WriteString()

Ahora en WriteString() . A menudo queremos escribir datos textuales en un io.Writer . Sí, podemos hacerlo simplemente convirtiendo la string a un []byte , por ejemplo

w.Write([]byte("Hello"))

que funciona como se espera. Sin embargo, esta es una operación muy frecuente y, por lo tanto, hay un método "generalmente" aceptado para esto capturado por la interfaz no io.stringWriter :

type stringWriter interface { WriteString(s string) (n int, err error) }

Este método ofrece la posibilidad de escribir un valor de string lugar de un []byte . Entonces, si algo (que también implementa io.Writer ) implementa este método, simplemente puede pasar valores de string sin la conversión de []byte . Esto parece una simplificación menor en el código, pero es más que eso. La conversión de una string a []byte tiene que hacer una copia del contenido de la string (porque string valores de la string son inmutables en Go), por lo que hay una sobrecarga que se hace notable si la string es "más grande" y / o tienes que hacer esto muchos veces.

Dependiendo de la naturaleza y los detalles de implementación de un io.Writer , puede ser que sea posible escribir el contenido de una string sin convertirla a []byte y, por lo tanto, evitar la sobrecarga mencionada anteriormente.

Como ejemplo, si un io.Writer es algo que se escribe en un búfer en memoria ( bytes.Buffer . El bytes.Buffer es un ejemplo de este tipo), puede utilizar la función integrada copy() :

La función integrada de copia copia elementos de un sector de origen a un sector de destino. (Como un caso especial, también copiará bytes de una cadena a una porción de bytes).

La copy() se puede usar para copiar el contenido (bytes) de una string en un []byte sin convertir la string en el []byte , por ejemplo:

buf := make([]byte, 100) copy(buf, "Hello")

Ahora hay una función "utilidad" io.WriteString() que escribe una string en un io.Writer . Pero lo hace comprobando primero si el (tipo dinámico de) pasado io.Writer tiene un método WriteString() , y si es así, se usará (cuya implementación es probablemente más eficiente). Si el io.Writer pasado no tiene tal método, entonces el método general de conversión a byte-slice-and-write-it-that-way se usará como un "respaldo".

Podría pensar que este WriteString() solo prevalecerá en el caso de búferes en memoria, pero eso no es cierto. Las respuestas de las solicitudes web a menudo también se almacenan en búfer (utilizando un búfer en memoria), por lo que puede mejorar el rendimiento en el caso de http.ResponseWriter también. Y si nos fijamos en la implementación de http.ResponseWriter : es el tipo no http.response ( server.go actualmente la línea # 308) que implementa WriteString() (actualmente la línea # 1212) por lo que significa una mejora.

En general, siempre que escriba valores de string , se recomienda utilizar io.WriteString() ya que puede ser más eficiente (más rápido).

fmt.Fprintf()

Debe considerar esto como una manera conveniente y fácil de agregar más formato a los datos que desea escribir, a cambio de ser algo menos eficiente.

Así que use fmt.Fprintf() si desea crear una string formateada de manera fácil, por ejemplo:

name := "Bob" age := 23 fmt.Fprintf(w, "Hi, my name is %s and I''m %d years old.", name, age)

Lo que resultará en la siguiente string a escribir:

Hi, my name is Bob and I''m 23 years old.

Una cosa que no debes olvidar: fmt.Fprintf() espera una cadena de formato , por lo que se procesará previamente y no se escribirá como está en la salida. Como un ejemplo rápido:

fmt.Fprintf(w, "100 %%")

Se esperaría que se escribiera "100 %%" en la salida (con 2 % caracteres), pero solo se enviará uno, ya que en la cadena de formato % es un carácter especial y %% solo dará como resultado uno en la salida .

Si solo desea escribir una string usando el paquete fmt , use fmt.Fprint() que no requiere una string formato:

fmt.Fprint(w, "Hello")

Otra ventaja de usar el paquete fmt es que también puede escribir valores de otros tipos, no solo string , por ejemplo

fmt.Fprint(w, 23, time.Now())

(Por supuesto, las reglas sobre cómo convertir cualquier valor a una string –y eventualmente a una serie de fmt están bien definidas, en el documento del paquete fmt ).

Para salidas con formato "simples", el paquete fmt podría estar bien. Para documentos de salida complejos, considere usar el text/template (para texto general) y html/template (siempre que la salida sea HTML).

Pasando / entregando http.ResponseWriter

Para completar, debemos mencionar que a menudo el contenido que desea enviar, ya que la respuesta de la web es generado por "algo" que admite "transmitir" el resultado. Un ejemplo puede ser una respuesta JSON, que se genera a partir de una estructura o mapa.

En tales casos, a menudo es más eficiente pasar / entregar su http.ResponseWriter que es un io.Writer a este algo si es compatible con la escritura del resultado en un io.Writer sobre la marcha.

Un buen ejemplo de esto es generar respuestas JSON. Claro, puedes convertir un objeto en JSON con json.Marshal() , que te devuelve una porción de bytes, que puedes enviar simplemente llamando a ResponseWriter.Write() .

Sin embargo, es más eficiente que el paquete json sepa que tiene un io.Writer y que, en última instancia, desea enviar el resultado a eso. De esa manera, no es necesario generar primero el texto JSON en un búfer, que solo escribe en su respuesta y luego descarta. Puede crear un nuevo json.Encoder llamando a json.NewEncoder() al que puede pasar su http.ResponseWriter como un io.Writer , y al llamar a Encoder.Encode() , escribirá directamente el resultado JSON en su escritor de respuestas.

Una desventaja aquí es que si la generación de la respuesta JSON falla, es posible que tenga una respuesta parcialmente enviada / confirmada que no puede retirar. Si este es un problema para usted, no tiene otra opción más que generar la respuesta en un búfer, y si el cálculo de referencias se realiza correctamente, puede escribir la respuesta completa de una vez.

He visto tres formas de escribir contenido en la respuesta HTTP:

func Handler(w http.ResponseWriter, req *http.Request) { io.WriteString(w, "blabla./n") }

Y:

func Handler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("blabla/n")) }

También hay:

fmt.Fprintf(w, "blabla")

¿Cual es la diferencia entre ellos? ¿Cuál se prefiere usar?


Como puede ver desde http.ResponseWriter , es una interfaz con el método Write([]byte) (int, error) .

Por lo tanto, en io.WriteString y fmt.Fprintf ambos están tomando io.Writer como primer argumento, que también es un método de Write(p []byte) (n int, err error) envuelve la interfaz

type Writer interface { Write(p []byte) (n int, err error) }

Entonces, cuando llame a io.WriteString (w, "blah") io.WriteString()

func WriteString(w Writer, s string) (n int, err error) { if sw, ok := w.(stringWriter); ok { return sw.WriteString(s) } return w.Write([]byte(s)) }

o fmt.Fprintf (w, "blabla") fmt.Fprintf()

func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrintf(format, a) n, err = w.Write(p.buf) p.free() return }

solo está llamando al método de escritura indirectamente a medida que pasa la variable ResponseWriter en ambos métodos.

Entonces, ¿por qué no llamarlo directamente usando w.Write([]byte("blabla/n")) . Espero que tengas tu respuesta.

PD: también hay una forma diferente de usar eso, si quieres enviarlo como respuesta JSON.

json.NewEncoder(w).Encode(wrapper) //Encode take interface as an argument. Wrapper can be: //wrapper := SuccessResponseWrapper{Success:true, Data:data}