Respostas:
EDITAR:
Desde a versão 1.10, existe o strings.Builder. Exemplo:
buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())
INFORMAÇÃO ATUALIZADA ABAIXO
A resposta curta é que não será eficiente, pois a conversão para uma string exige uma cópia completa da matriz de bytes. Aqui está a maneira correta (não eficiente) de fazer o que você deseja:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.
Esta cópia é feita como um mecanismo de proteção. Strings são imutáveis. Se você pudesse converter um byte [] em uma string, poderia alterar o conteúdo da string. No entanto, o go permite desativar os mecanismos de segurança de tipo usando o pacote não seguro. Use o pacote não seguro por sua conta e risco. Espero que o nome por si só seja um aviso suficientemente bom. Aqui está como eu faria isso usando inseguro:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
Lá vamos nós, agora você converteu eficientemente sua matriz de bytes em uma string. Realmente, tudo o que isso faz é induzir o sistema de tipos a chamá-lo de string. Existem algumas ressalvas nesse método:
Meu conselho é seguir o método oficial. Fazendo uma cópia não é que caro e não vale a pena os males do inseguro. Se a sequência for muito grande para fazer uma cópia, você não deve transformá-la em uma sequência.
strings.Builderfaz isso de maneira eficiente, garantindo que o subjacente []bytenunca vaze e convertendo para stringsem uma cópia de uma maneira que seja suportada no futuro. Isso não existia em 2012. A solução da @ dimchansky abaixo foi a correta desde o Go 1.10. Considere uma edição!
Até agora, as respostas não abordaram a parte "stream inteiro" da pergunta. Eu acho que a boa maneira de fazer isso é ioutil.ReadAll. Com o seu io.ReaderClosernome rc, eu escreveria,
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
buf.ReadFrom()também lê todo o fluxo até o EOF.
ioutil.ReadAll()e simplesmente envolve um bytes.Buffer's ReadFrom. E o String()método do buffer é uma quebra simples da conversão para string- portanto, as duas abordagens são praticamente as mesmas!
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
A maneira mais eficiente seria sempre usar em []bytevez de string.
Caso você precise imprimir dados recebidos do io.ReadCloser, o fmtpacote pode manipular []byte, mas não é eficiente porque a fmtimplementação será convertida internamente []byteem string. Para evitar essa conversão, você pode implementar a fmt.Formatterinterface para um tipo como type ByteSlice []byte.
[]bytepara stringé razoavelmente rápida, mas a pergunta estava sendo feita "da maneira mais eficiente". Atualmente, o tempo de execução Go sempre aloca um novo stringao converter []bytepara string. A razão para isso é que o compilador não sabe como determinar se o []byteserá modificado após a conversão. Há espaço para otimizações do compilador aqui.
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()
Eu gosto da estrutura bytes.Buffer . Eu vejo que ele tem métodos ReadFrom e String . Eu usei com um byte [], mas não com um io.Reader.