Відповіді:
Редагувати:
З 1.10 існує рядки strings.Builder. Приклад:
buf := new(strings.Builder)
n, err := io.Copy(buf, r)
// check errors
fmt.Println(buf.String())
ВИПУСКОВА ІНФОРМАЦІЯ ВІДНІ
Коротка відповідь полягає в тому, що це не буде ефективно, оскільки для перетворення в рядок потрібно зробити повну копію байтового масиву. Ось правильний (неефективний) спосіб робити те, що ви хочете:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
s := buf.String() // Does a complete copy of the bytes in the buffer.
Ця копія робиться як механізм захисту. Струни незмінні. Якщо ви могли перетворити байт [] в рядок, ви можете змінити вміст рядка. Однак функція go дозволяє відключити механізми безпеки типу за допомогою небезпечного пакету. Використовуйте небезпечний пакет на свій страх і ризик. Сподіваємось, саме ім'я є досить хорошим попередженням. Ось як я це зробив за допомогою небезпечних:
buf := new(bytes.Buffer)
buf.ReadFrom(yourReader)
b := buf.Bytes()
s := *(*string)(unsafe.Pointer(&b))
Зараз ми вже зараз ефективно перетворили свій байтовий масив у рядок. Дійсно, все це полягає в хитрості типової системи називати її рядком. Існує пара застережень до цього методу:
Моя порада - дотримуватися офіційного методу. Робити копією не що дорого , і це не варто вад небезпечних. Якщо рядок занадто великий, щоб зробити копію, не слід перетворювати її на рядок.
strings.Builderробить це ефективно, гарантуючи, що базові []byteніколи не протікають, і перетворюючись на stringбез копії таким чином, що буде підтримуватися вперед. Цього не існувало у 2012 році. Розв’язання димчанського нижче було правильним з Go 1.10. Будь ласка, розгляньте правку!
Досі відповіді не стосувались частини питання "весь потік". Я думаю, що хороший спосіб зробити це ioutil.ReadAll. З вашим io.ReaderCloserназваним rcя б написав:
if b, err := ioutil.ReadAll(rc); err == nil {
return string(b)
} ...
buf.ReadFrom()також читає весь потік аж до EOF.
ioutil.ReadAll()і просто обгортання bytes.Buffer«S ReadFrom. А буферний String()метод - це просте обертання навколо кастингу, stringтому два підходи практично однакові!
data, _ := ioutil.ReadAll(response.Body)
fmt.Println(string(data))
Найефективнішим способом було б завжди використовувати []byteзамість цього string.
У випадку, якщо вам потрібно буде надрукувати дані, отримані від io.ReadCloser, fmtпакет може обробляти []byte, але це не ефективно, тому що fmtреалізація буде внутрішньо перетворена []byteв string. Щоб уникнути цього перетворення, ви можете реалізувати fmt.Formatterінтерфейс для такого типу type ByteSlice []byte.
[]byteдо stringдосить швидко, але питання було "про найефективніший спосіб". В даний час час запуску Go завжди виділяє нове stringпри переході []byteна string. Причиною цього є те, що компілятор не знає, як визначити, чи []byteбуде змінено засіб після перетворення. Тут є місце для оптимізації компілятора.
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()