liblogic bytes что это
Разбираемся в Go: пакет io
Перевод одной из статей Бена Джонсона из серии «Go Walkthrough» по более углублённому изучению стандартной библиотеки в контексте реальных задач.
Go является языком программирования, хорошо приспособленным для работы с байтами. Будь у вас списки байт, потоки байт или просто отдельные байты, в Go легко с ними работать. Это примитивы, на которых мы строим наши абстракции и сервисы.
Пакет io является одним из самых фундаментальных во всей стандартной библиотеке. Он предоставляет набор интерфейсов и вспомогательных функций для работы с потоками байтов.
Этот пост является одним из серии статей по более углублённому разбору стандартной библиотеки. Несмотря на то, что стандартная документация предоставляет массу полезной информации, в контексте реальных задач может быть непросто разобраться, что и когда использовать. Эта серия статей направлена на то, чтобы показать использование пакетов стандартной библиотеки в контексте реальных приложений.
Чтение байтов
При работе с байтами, есть две фундаментальные операции: чтение и запись. Давайте сначала взглянём на чтение байтов.
Интерфейс Reader
Простейшая конструкция для чтения байтов из потока это интерфейс Reader:
Этот интерфейс многократно реализован в стандартной библиотеке для вообще всего — от сетевых соединений, до файлов и до врапперов для слайсов в памяти.
Reader принимает на вход буфер, p, как параметр для метода Read(), чтобы не нужно было выделять память. Если бы Read() возвращал новый слайс, вместо того, чтобы принимать его как аргумент, ридеру пришлось бы выделять память при каждом вызове Read(). Это была бы катастрофа для сборщика мусора.
Одна из проблем с интерфейсом Reader в том, что с ним идёт набор довольно витиеватых правил. Во-первых, он возвращает ошибку io.EOF при нормальном ходе дел, просто если поток данных завершился. Это может запутывать новичков. Во-вторых, нет гарантии, что ваш буфер будет заполнен целиком. Если вы передали 8-байтовый слайс, по факту вы можете прочитать от 0 до 8 байт. Обработка чтения по частям можем быть непростой и легко подвержена ошибкам. К счастью, у нас есть немало вспомогательных функций для решения этих задач.
Улучшаем гарантии чтения
Представим, что у вас есть протокол, который нужно распарсить и вы хотите прочесть 8-байтовое uint64 значение из ридера. В этом случае предпочтительней использовать io.ReadFull(), так как вы точно знаете, сколько хотите прочесть:
Эта функция проверяет, что буфер полностью заполнен перед тем, как вернуть значение. Если размер полученных данных отличается от размера буфера, то вы получите ошибку io.ErrUnexpectedEOF. Эта простая гарантия упрощает код довольно сильно. Чтобы прочесть 8 байт, достаточно сделать так:
Есть также довольно много более высокоуровневых парсеров вроде binary.Read(), которые умеют парсить определённые типы. Мы познакомимся ближе с ними в следующих постах о других пакетах.
Ещё одна чуть реже используемая вспомогательная функция это ReadAtLeast():
Эта функция записывает доступные для чтения данные в ваш буфер, но не менее указанного количества байт. Я не нашел надобности в этой функции лично для себя, но легко могу представить её пользу для случаев, когда вы хотите уменьшить количество вызовов Read() и буферизировать дополнительные данные.
Объединение потоков
Нередко вы можете встретить ситуацию, где вам необходимо объединить несколько ридеров вместе. Это легко сделать с помощью MultiReader:
Например, вы хотите отправить HTTP ответ, в котором заголовок читается из памяти, а содержимое тела ответа — из файла. Многие люди сначала прочитают файл в буфер в памяти перед отправкой, но это медленно и может требовать много памяти.
Вот более простой подход:
MultiReader даёт возможность http.Post() использовать оба ридера как один.
Дублирование потоков
Один из моментов, которые вам могут встретиться при работе с ридерами это то, что если данные были вычитаны, их нельзя прочитать ещё раз. Например, ваше приложение не смогло распарсить тело HTTP запроса, но вы не можете его проанализировать, потому что парсер уже прочёл данные, их больше нет в ридере.
TeeReader является тут хорошим решением — он позволяет сохранять вычитанные данные, при этом не мешая процессу чтения.
Эта функция создаёт новый ридер-обёртку вокруг вашего ридера r. Любая операция чтения из нового ридера будет также записывать данные в w. Этот райтер(writer) может представлять собой всё что угодно — от буфера в памяти, до лог файла и до потока стандартных ошибок STDERR.
Например, вы можете захватывать ошибочные запросы следующим образом:
Впрочем, тут важно быть внимательными с размерами вычитанного тела ответа, чтобы не израсходовать память.
Ограничение длины потока
Поскольку потоки никак не ограничены по размеру, иногда чтение из них может привести к проблемам с памятью или местом на диске. Типичный пример это хендлер, осуществляющий загрузку файла. Обычно существуют лимиты на максимальный размер загружаемого файла, чтобы не переполнять диск, но может быть утомительно имплементировать их вручную.
LimitReader даёт нам эту функциональность, предоставляя обёртку вокруг ридера, который ограничивает количество байт, доступных для вычитки.
Один из моментов при работе с LimitReader-ом это то, что он не скажет вам, если r вычитал больше, чем n. Он просто вернёт io.EOF, как только вычитает n байт. Как вариант, можно выставить лимит в n+1 и потом проверить, прочитали ли вы больше, чем n байт в конце.
Запись байтов
Теперь, после того как мы познакомились с чтением байтов из потоков, давайте посмотрим, как их записывать в потоки.
Интерфейс Writer
Интерфейс Writer это, по сути, инвертированный Reader. Мы указываем набор байтов, которые нужно записать в поток:
В общем случае, запись байтов это более простая операция, чем чтение. С ридерами сложность в том, чтобы правильно работать с частичными и не полными чтениями, но при частичной или неполной записи, мы просто получаем ошибку.
Дублирование записи
Иногда вам нужно отправить данные сразу в несколько writer-ов. Например, в лог файл и в STDERR. Это похоже на TeeReader, только мы хотим дублировать запись, а не чтение.
В этом случае нам подойдёт MultiWriter:
Имя может немного сбивать толку, потому что это не совсем writer-версия MultiReader. Если MultiReader объединяет несколько ридеров в один, то MultiWriter возвращает writer, который дублирует записи во все writer-ы.
Я активно использую MultiWriter в unit-тестах, где я хочу убедиться, что сервисы пишут в лог корректно:
Использование MultiWriter позволяет мне проверить содержимое buf и при этом видеть полный вывод логов в терминале для отладки.
Копирование байт
Теперь, когда мы разобрались и с чтением, и с записью байт, логично разобраться, как мы можем объединять эти две операции вместе и копировать данные между ними.
Объединяя readers & writers
Самый простой способ скопировать из ридера во writer это использовать функцию Copy():
Эта функция использует буфер в 32 КБ, чтобы прочитать из src и записать в dst. Если случится ошибка, отличная от io.EOF, копирование остановится и вернётся ошибка.
Одна из проблем с Copy() заключается в том, что у вас нет способа гарантировать максимальное количество скопированных байт. Например, вы хотите скопировать лог файл до его текущего размера. Если же лог продолжит расти во время копирования, вы получите больше байт, чем ожидалось. В этом случае можно использовать функцию CopyN(), которая скопирует не больше указанного количества:
Ещё один важный момент с Copy() заключается в том, что при каждом копировании выделяется буфер в 32КБ. Если вам нужно делать много операций копирования, вы можете переиспользовать уже выделенный буфер и использовать CopyBuffer():
Накладные расходы на Copy() на самом деле очень малы, поэтому я лично не использую CopyBuffer().
Оптимизируем копирование
Чтобы избежать использования промежуточного буфера, типы данных могут имплементировать специальные интерфейсы для чтения и записи в них напрямую. Если они имплементированы для типа, функция Copy() не будет использовать буфер, а будет использовать эти специальные методы.
Если тип имплементирует интерфейс WriterTo, то он может записывать данные напрямую:
Я использовал его в функции BoltDB Tx.WriteTo(), которая позволяет пользователям создавать снапшот базы данных из транзакции.
С другой стороны, интерфейс ReaderFrom позволяет типу напрямую читать данные из ридера:
Адаптация ридеров и райтеров
Иногда вы оказываетесь в ситуации, когда у вас есть функция, принимающая Reader, но у вас есть только Writer. Возможно, вы хотите динамически записать данные в HTTP запрос, но http.NewRequest() принимает только Reader.
Вы можете инвертировать райтер, используя io.Pipe():
Тут вы получаете новый ридер и writer. Любая запись в PipeWriter переправится в PipeReader.
Я редко использовал эту функцию, но exec.Cmd использует её для реализации Stdin, Stdout и Stderr пайпов, которые могут быть очень полезны при работе c запускаемыми программами.
Закрытие потоков
Всё хорошее подходит к концу, и работа с потоками не исключение. Интерфейс Closer предоставляет общий способ закрывать потоки:
Тут особо не о чем писать, интерфейс этот очень простой, но я стараюсь всегда возвращать ошибку в моих Close() методах, чтобы мои типы реализовывали этот интерфейс, если потребуется. Closer не всегда используется напрямую, он чаще идёт в сочетании с другими интерфейсами, такими как ReadCloser, WriteCloser и ReadWriteCloser.
Навигация по потокам
Потоки обычно представляют собой постоянно появляющиеся данные от начала до конца, но бывают исключения. Файл, к примеру, может быть потоком, но при этом вы также можете произвольно перемещаться к любой позиции внутри файла.
Интерфейс Seeker предоставляет возможность перемещаться внутри потока:
Есть три способа прыгать на нужную позицию: переход от текущей позиции, переход с начала потока и переход с конца. Вы указываете этот способ аргументом whence. Аргумент offset указывает на сколько байт переместиться.
Перемещение по потоку может быть полезным, если вы используете блоки фиксированного размера или если ваш файл содержит индекс со смещениями. Иногда данные находятся в заголовке и логично использовать переход с начала потока, но иногда данные находятся в хвосте и удобнее перемещаться с конца.
Оптимизация под типы данных
Чтение и запись порциями могут быть утомительны, если всё что вам нужно это один байт или руна (rune). В Go для этого есть интерфейсы, которые облегчают жизнь.
Работа с индивидуальными байтами
Интерфейсы ByteReader и ByteWriter предоставляют простые методы для чтения и записи одного байта:
Заметьте, что тут нет параметра для количества байт, это всегда будет 0 или 1. Если байт не был прочитан или записан, возвращается ошибка.
Также есть есть ByteScanner интерфейс, позволяющий удобно работать с буферизированными ридерами для байт:
Этот интерфейс позволяет вернуть байт обратно в поток. Это бывает удобно, например при написании LL(1) парсеров, так как позволяет заглядывать на байт вперёд.
Работа с индивидуальными рунами
Если вы парсите Unicode данные, то вы должны работать с рунами вместо индивидуальных байт. В этом случае вы должны использовать интерфейсы RuneReader и RuneScanner:
Вывод
Потоки байт важны для многих Go программ. Это интерфейсы для всего, от сетевых соединений до файлов на диске и до пользовательского ввода с клавиатуры. Пакет io предоставляет основные примитивы для работы со всем этим.
Мы посмотрели на чтение, запись и копирование байт, а также на оптимизацию этих операций под конкретные задачи. Эти примитивы могут выглядеть просто, но они являются базовыми строительными блоками для приложений, активно работающих с данными.
Пожалуйста, изучите внимательно пакет io и используйте его интерфейсы в своих программах. Также я буду рад, если вы поделитесь своими интересными способами использования пакета io, равно как и любым советам по тому, как можно улучшить эту серию статей.
GoLang bytes – variable and package
Bytes are a data type in GoLang. In this post, we will explore bytes as well as slices of them, the bytes package itself and what can be done with it.
What is a byte variable?
A byte in Go is simply an unsigned 8-bit integer. That means it has a limit of (0 – 255) in numerical range. In Go, a byte can represent a character from a string as well.
Creating a byte variable
The syntax for declaring a byte is really simple all is needed is to declare it as a byte variable and then use it.
Zero value of a byte
The zero value of a byte is simply zero (0).
Using bytes with strings
Bytes can be converted to and from strings in Go. This is very useful in certain cases. Here is an example of using bytes along with strings.
GoLang “bytes” package
The “bytes” package implements many useful functions that can be used to manipulate byte slices. It also contains a type Buffer which is an important struct that we will be exploring later on. Here are some of the most useful functions that can be used with byte slices.
1. Compare byte slices
The Compare(b1, b2 []byte) function compares byte slices lexicographically and returns int based on the following ruleset:
2. Check if a byte slice is a subslice of other
The Contains(s, a byte[]) function is used to check if a slice is subslice of another slice. Here is an example.
3. Check if a byte slice contains the rune
The ContainsRune(b []byte, r rune) function is used to check whether a byte slice contains a rune.
4. Check for equality of byte slices
The Equal(a, b []byte) function takes two-byte slices and returns true if they are equal.
The function EqualFold checks whether two-byte slices are equal even if they are different cased.
5. The “Fields” function
The Fields function separates a byte slice by whitespace it contains.
6. The “Index” function
7. Join byte slices
The join function takes an array of a byte slice and joins them with a separator that it takes as an argument.
8. The repeat function
The repeat function simply repeats the slice the number of times it gets as an argument.
9. The “Split” function
The split function uses the separator to split the string into an array of string.
10. Trimming the slice
The slice can be trimmed off anything we use by simply using the trim function. Here is the way to do that.
Go bytes.Buffer type
The buffer is a useful struct which is very efficient. The Buffer type comes with the bytes package. Here is the syntax for declaring an empty buffer.
To write into a Buffer we can use the write function like this.
The Fprintf can also be used to write into the buffer.
There are some functions that can be used with the Buffer type. This comes useful for many different scenarios. Here we are going to explore some of them.
There are multiple write functions for different types of data like strings, runes, etc in the Buffer type.
These are some of the most common use cases of bytes in Go.
Package bytes
Overview ▸
Overview ▾
Package bytes implements functions for the manipulation of byte slices. It is analogous to the facilities of the strings package.
Index ▸
Index ▾
Examples (Expand All)
Package files
Constants
MinRead is the minimum slice size passed to a Read call by Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond what is required to hold the contents of r, ReadFrom will not grow the underlying buffer.
smallBufferSize is an initial allocation minimal capacity.
Variables
ErrTooLarge is passed to panic if memory cannot be allocated to store data in a buffer.
func Compare ¶
func Contains ¶
Contains reports whether subslice is within b.
func ContainsAny ¶ 1.7
ContainsAny reports whether any of the UTF-8-encoded code points in chars are within b.
func ContainsRune ¶ 1.7
ContainsRune reports whether the rune is contained in the UTF-8-encoded byte slice b.
func Count ¶
Count counts the number of non-overlapping instances of sep in s. If sep is an empty slice, Count returns 1 + the number of UTF-8-encoded code points in s.
func Equal ¶
Equal reports whether a and b are the same length and contain the same bytes. A nil argument is equivalent to an empty slice.
func EqualFold ¶
EqualFold reports whether s and t, interpreted as UTF-8 strings, are equal under Unicode case-folding, which is a more general form of case-insensitivity.
func Fields ¶
Fields interprets s as a sequence of UTF-8-encoded code points. It splits the slice s around each instance of one or more consecutive white space characters, as defined by unicode.IsSpace, returning a slice of subslices of s or an empty slice if s contains only white space.
func FieldsFunc ¶
FieldsFunc interprets s as a sequence of UTF-8-encoded code points. It splits the slice s at each run of code points c satisfying f(c) and returns a slice of subslices of s. If all code points in s satisfy f(c), or len(s) == 0, an empty slice is returned.
FieldsFunc makes no guarantees about the order in which it calls f(c) and assumes that f always returns the same value for a given c.
func HasPrefix ¶
HasPrefix tests whether the byte slice s begins with prefix.
func HasSuffix ¶
HasSuffix tests whether the byte slice s ends with suffix.
func Index ¶
func IndexAny ¶
func IndexByte ¶
func IndexFunc ¶
func IndexRune ¶
func Join ¶
Join concatenates the elements of s to create a new byte slice. The separator sep is placed between elements in the resulting slice.
func LastIndex ¶
func LastIndexAny ¶
func LastIndexByte ¶ 1.5
func LastIndexFunc ¶
func Map ¶
Map returns a copy of the byte slice s with all its characters modified according to the mapping function. If mapping returns a negative value, the character is dropped from the byte slice with no replacement. The characters in s and the output are interpreted as UTF-8-encoded code points.
func Repeat ¶
Repeat returns a new byte slice consisting of count copies of b.
It panics if count is negative or if the result of (len(b) * count) overflows.
func Replace ¶
Replace returns a copy of the slice s with the first n non-overlapping instances of old replaced by new. If old is empty, it matches at the beginning of the slice and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune slice. If n Example
func ReplaceAll ¶ 1.12
ReplaceAll returns a copy of the slice s with all non-overlapping instances of old replaced by new. If old is empty, it matches at the beginning of the slice and after each UTF-8 sequence, yielding up to k+1 replacements for a k-rune slice.
func Runes ¶
Runes interprets s as a sequence of UTF-8-encoded code points. It returns a slice of runes (Unicode code points) equivalent to s.
func Split ¶
func SplitAfter ¶
func SplitAfterN ¶
SplitAfterN slices s into subslices after each instance of sep and returns a slice of those subslices. If sep is empty, SplitAfterN splits after each UTF-8 sequence. The count determines the number of subslices to return:
func SplitN ¶
SplitN slices s into subslices separated by sep and returns a slice of the subslices between those separators. If sep is empty, SplitN splits after each UTF-8 sequence. The count determines the number of subslices to return:
func Title ¶
Title treats s as UTF-8-encoded bytes and returns a copy with all Unicode letters that begin words mapped to their title case.
BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
func ToLower ¶
ToLower returns a copy of the byte slice s with all Unicode letters mapped to their lower case.
func ToLowerSpecial ¶
ToLowerSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their lower case, giving priority to the special casing rules.
func ToTitle ¶
ToTitle treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case.
func ToTitleSpecial ¶
ToTitleSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their title case, giving priority to the special casing rules.
func ToUpper ¶
ToUpper returns a copy of the byte slice s with all Unicode letters mapped to their upper case.
func ToUpperSpecial ¶
ToUpperSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their upper case, giving priority to the special casing rules.
func ToValidUTF8 ¶ 1.13
ToValidUTF8 treats s as UTF-8-encoded bytes and returns a copy with each run of bytes representing invalid UTF-8 replaced with the bytes in replacement, which may be empty.
func Trim ¶
Trim returns a subslice of s by slicing off all leading and trailing UTF-8-encoded code points contained in cutset.
func TrimFunc ¶
TrimFunc returns a subslice of s by slicing off all leading and trailing UTF-8-encoded code points c that satisfy f(c).
func TrimLeft ¶
TrimLeft returns a subslice of s by slicing off all leading UTF-8-encoded code points contained in cutset.
func TrimLeftFunc ¶
TrimLeftFunc treats s as UTF-8-encoded bytes and returns a subslice of s by slicing off all leading UTF-8-encoded code points c that satisfy f(c).
func TrimPrefix ¶ 1.1
TrimPrefix returns s without the provided leading prefix string. If s doesn’t start with prefix, s is returned unchanged.
func TrimRight ¶
TrimRight returns a subslice of s by slicing off all trailing UTF-8-encoded code points that are contained in cutset.
func TrimRightFunc ¶
TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8-encoded code points c that satisfy f(c).
func TrimSpace ¶
TrimSpace returns a subslice of s by slicing off all leading and trailing white space, as defined by Unicode.
func TrimSuffix ¶ 1.1
TrimSuffix returns s without the provided trailing suffix string. If s doesn’t end with suffix, s is returned unchanged.
func explode ¶
explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes), up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
func genSplit ¶
Generic split: splits after each instance of sep, including sepSave bytes of sep in the subslices.
func indexBytePortable ¶
func indexFunc ¶
indexFunc is the same as IndexFunc except that if truth==false, the sense of the predicate function is inverted.
func isSeparator ¶
isSeparator reports whether the rune could mark a word boundary. TODO: update when package unicode captures more of the properties.
func lastIndexFunc ¶
lastIndexFunc is the same as LastIndexFunc except that if truth==false, the sense of the predicate function is inverted.
func makeCutsetFunc ¶
func makeSlice ¶
makeSlice allocates a slice of size n. If the allocation fails, it panics with ErrTooLarge.
type Buffer ¶
A Buffer is a variable-sized buffer of bytes with Read and Write methods. The zero value for Buffer is an empty buffer ready to use.
func NewBuffer ¶
NewBuffer creates and initializes a new Buffer using buf as its initial contents. The new Buffer takes ownership of buf, and the caller should not use buf after this call. NewBuffer is intended to prepare a Buffer to read existing data. It can also be used to set the initial size of the internal buffer for writing. To do that, buf should have the desired capacity but a length of zero.
In most cases, new(Buffer) (or just declaring a Buffer variable) is sufficient to initialize a Buffer.
func NewBufferString ¶
NewBufferString creates and initializes a new Buffer using string s as its initial contents. It is intended to prepare a buffer to read an existing string.
In most cases, new(Buffer) (or just declaring a Buffer variable) is sufficient to initialize a Buffer.
func (*Buffer) Bytes ¶
Bytes returns a slice of length b.Len() holding the unread portion of the buffer. The slice is valid for use only until the next buffer modification (that is, only until the next call to a method like Read, Write, Reset, or Truncate). The slice aliases the buffer content at least until the next buffer modification, so immediate changes to the slice will affect the result of future reads.
func (*Buffer) Cap ¶ 1.5
Cap returns the capacity of the buffer’s underlying byte slice, that is, the total space allocated for the buffer’s data.
func (*Buffer) Grow ¶ 1.1
Grow grows the buffer’s capacity, if necessary, to guarantee space for another n bytes. After Grow(n), at least n bytes can be written to the buffer without another allocation. If n is negative, Grow will panic. If the buffer can’t grow it will panic with ErrTooLarge.
func (*Buffer) Len ¶
Len returns the number of bytes of the unread portion of the buffer; b.Len() == len(b.Bytes()).
func (*Buffer) Next ¶
Next returns a slice containing the next n bytes from the buffer, advancing the buffer as if the bytes had been returned by Read. If there are fewer than n bytes in the buffer, Next returns the entire buffer. The slice is only valid until the next call to a read or write method.
func (*Buffer) Read ¶
Read reads the next len(p) bytes from the buffer or until the buffer is drained. The return value n is the number of bytes read. If the buffer has no data to return, err is io.EOF (unless len(p) is zero); otherwise it is nil.
func (*Buffer) ReadByte ¶
ReadByte reads and returns the next byte from the buffer. If no byte is available, it returns error io.EOF.
func (*Buffer) ReadBytes ¶
func (*Buffer) ReadFrom ¶
ReadFrom reads data from r until EOF and appends it to the buffer, growing the buffer as needed. The return value n is the number of bytes read. Any error except io.EOF encountered during the read is also returned. If the buffer becomes too large, ReadFrom will panic with ErrTooLarge.
func (*Buffer) ReadRune ¶
ReadRune reads and returns the next UTF-8-encoded Unicode code point from the buffer. If no bytes are available, the error returned is io.EOF. If the bytes are an erroneous UTF-8 encoding, it consumes one byte and returns U+FFFD, 1.
func (*Buffer) ReadString ¶
func (*Buffer) Reset ¶
Reset resets the buffer to be empty, but it retains the underlying storage for use by future writes. Reset is the same as Truncate(0).
func (*Buffer) String ¶
String returns the contents of the unread portion of the buffer as a string. If the Buffer is a nil pointer, it returns » «.
To build strings more efficiently, see the strings.Builder type.
func (*Buffer) Truncate ¶
Truncate discards all but the first n unread bytes from the buffer but continues to use the same allocated storage. It panics if n is negative or greater than the length of the buffer.
func (*Buffer) UnreadByte ¶
UnreadByte unreads the last byte returned by the most recent successful read operation that read at least one byte. If a write has happened since the last read, if the last read returned an error, or if the read read zero bytes, UnreadByte returns an error.
func (*Buffer) UnreadRune ¶
UnreadRune unreads the last rune returned by ReadRune. If the most recent read or write operation on the buffer was not a successful ReadRune, UnreadRune returns an error. (In this regard it is stricter than UnreadByte, which will unread the last byte from any read operation.)
func (*Buffer) Write ¶
Write appends the contents of p to the buffer, growing the buffer as needed. The return value n is the length of p; err is always nil. If the buffer becomes too large, Write will panic with ErrTooLarge.
func (*Buffer) WriteByte ¶
WriteByte appends the byte c to the buffer, growing the buffer as needed. The returned error is always nil, but is included to match bufio.Writer’s WriteByte. If the buffer becomes too large, WriteByte will panic with ErrTooLarge.
func (*Buffer) WriteRune ¶
WriteRune appends the UTF-8 encoding of Unicode code point r to the buffer, returning its length and an error, which is always nil but is included to match bufio.Writer’s WriteRune. The buffer is grown as needed; if it becomes too large, WriteRune will panic with ErrTooLarge.
func (*Buffer) WriteString ¶
WriteString appends the contents of s to the buffer, growing the buffer as needed. The return value n is the length of s; err is always nil. If the buffer becomes too large, WriteString will panic with ErrTooLarge.
func (*Buffer) WriteTo ¶
WriteTo writes data to w until the buffer is drained or an error occurs. The return value n is the number of bytes written; it always fits into an int, but it is int64 to match the io.WriterTo interface. Any error encountered during the write is also returned.
func (*Buffer) empty ¶
empty reports whether the unread portion of the buffer is empty.
func (*Buffer) grow ¶
grow grows the buffer to guarantee space for n more bytes. It returns the index where bytes should be written. If the buffer can’t grow it will panic with ErrTooLarge.
func (*Buffer) readSlice ¶
readSlice is like ReadBytes but returns a reference to internal buffer data.
func (*Buffer) tryGrowByReslice ¶
tryGrowByReslice is a inlineable version of grow for the fast-case where the internal buffer only needs to be resliced. It returns the index where bytes should be written and whether it succeeded.
type Reader ¶
A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, io.ByteScanner, and io.RuneScanner interfaces by reading from a byte slice. Unlike a Buffer, a Reader is read-only and supports seeking. The zero value for Reader operates like a Reader of an empty slice.
func NewReader ¶
NewReader returns a new Reader reading from b.
func (*Reader) Len ¶
Len returns the number of bytes of the unread portion of the slice.