Antworten:
BEARBEITEN:
Seit 1.10 existiert strings.Builder. Beispiel:
buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())
Veraltete Informationen unten
Die kurze Antwort lautet, dass dies nicht effizient ist, da für die Konvertierung in eine Zeichenfolge eine vollständige Kopie des Byte-Arrays erforderlich ist. Hier ist der richtige (nicht effiziente) Weg, um das zu tun, was Sie wollen:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.
Diese Kopie dient als Schutzmechanismus. Saiten sind unveränderlich. Wenn Sie ein [] Byte in eine Zeichenfolge konvertieren könnten, könnten Sie den Inhalt der Zeichenfolge ändern. Mit go können Sie jedoch die Typensicherheitsmechanismen mithilfe des unsicheren Pakets deaktivieren. Verwenden Sie das unsichere Paket auf eigenes Risiko. Hoffentlich ist der Name allein eine gute Warnung. So würde ich es mit unsicher machen:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
Jetzt haben Sie Ihr Byte-Array effizient in einen String konvertiert. Wirklich, alles, was dies tut, ist das Typsystem dazu zu bringen, es eine Zeichenfolge zu nennen. Diese Methode weist einige Einschränkungen auf:
Mein Rat ist, sich an die offizielle Methode zu halten. Eine Kopie zu machen ist nicht so teuer und das Übel der Unsicherheit nicht wert. Wenn die Zeichenfolge zu groß ist, um eine Kopie zu erstellen, sollten Sie sie nicht zu einer Zeichenfolge machen.
strings.Builder
Dies geschieht effizient, indem sichergestellt wird, dass der Basiswert []byte
niemals leckt, und string
ohne Kopie auf eine Weise konvertiert wird, die in Zukunft unterstützt wird. Dies gab es 2012 nicht. Die unten stehende Lösung von @ dimchansky ist seit Go 1.10 die richtige. Bitte überlegen Sie sich eine Bearbeitung!
Die Antworten haben bisher nicht den "gesamten Stream" -Teil der Frage angesprochen. Ich denke, der gute Weg, dies zu tun, ist ioutil.ReadAll
. Mit deinem io.ReaderCloser
Namen rc
würde ich schreiben,
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
buf.ReadFrom()
auch der gesamte Stream bis zu EOF gelesen.
ioutil.ReadAll()
und es verpackt einfach a bytes.Buffer
's ReadFrom
. Und die String()
Methode des Puffers ist ein einfaches Wrap-Around-Casting string
- die beiden Ansätze sind also praktisch gleich!
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
Der effizienteste Weg wäre, immer []byte
statt zu verwenden string
.
Im Fall , dass Sie Daten aus den empfangenen drucken io.ReadCloser
, das fmt
kann Paket handhaben []byte
, aber es ist nicht effizient , da die fmt
Implementierung intern konvertieren []byte
zu string
. Um diese Konvertierung zu vermeiden, können Sie die fmt.Formatter
Schnittstelle für einen Typ wie implementieren type ByteSlice []byte
.
[]byte
auf string
ist relativ schnell, aber die Frage lautete "der effizienteste Weg". Derzeit weist die Go-Laufzeit string
beim Konvertieren []byte
in immer eine neue zu string
. Der Grund dafür ist, dass der Compiler nicht weiß, wie er bestimmen soll, ob der []byte
nach der Konvertierung geändert wird. Hier gibt es Raum für Compiler-Optimierungen.
func copyToString(r io.Reader) (res string, err error) {
var sb strings.Builder
if _, err = io.Copy(&sb, r); err == nil {
res = sb.String()
}
return
}
var b bytes.Buffer
b.ReadFrom(r)
// b.String()
Ich mag die bytes.Buffer Struktur. Ich sehe, es hat ReadFrom- und String- Methoden. Ich habe es mit einem [] Byte verwendet, aber nicht mit einem io.Reader.