Відповіді:
Редагувати:
З 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()