Этикет длины буфера
У меня есть вопрос этикета. Я реализую RPC-сервер, поэтому эта функция принимает значение и использует переменную out в своем параметре. Эта функция читает из container/list
и заполняет обычный буфер массива для возврата через переменную out.
func (t *PersonalPlaylist) GetPlaylist(n int, reply *[]string) error {
t.listMutex.Lock()
bufLen := min(n, t.list.Len()) // mark
buf := make([]string, bufLen) // mark
e := t.list.Front()
for i := 0; i < n; i++ {
s := e.Value.(string)
buf[i] = fmt.Sprintf("String #%d: %s", i, s)
e = e.Next()
if e == nil {
break
}
}
*reply = buf
t.listMutex.Unlock()
return nil
}
[Обратите внимание, что эта функция должна ограничивать максимальный размер буфера.]
Особого внимания заслуживают отмеченные линии. Я пытаюсь решить, должен ли буфер всегда иметь запрошенный размер (n) и быть заполненным нулем / нулем сверх реальных данных, или же буфер иногда должен быть короче значения запроса.
Если размер буфера всегда запрошенный, код, вызывающий эту функцию, может использовать значение, переданное им в качестве параметра, как часть цикла через массив. Тем не менее, некоторые значения в массиве могут быть равны nil, поэтому в каждом цикле необходимо будет проверить nil:
for i := 0; i < n; i++ {
if reply[i] == nil {
break; // or continue
}
}
В альтернативном сценарии вызывающая сторона не может быть уверена в размере буфера и должна будет вызвать len(reply)
вместо этого, но можно в значительной степени гарантировать, что все значения будут отличны от нуля.
Я склоняюсь к использованию функции как есть и к тому, чтобы вызывающие абоненты не были уверены в длине буфера (при этом гарантируя максимально возможный размер буфера); Это связано прежде всего с тем, что это интерфейс относительно высокого уровня, который будет только повышаться по мере продолжения разработки. Есть ли соглашение, о котором я не знаю, что этот код нарушается? Или какой-то этикет, который подталкивает это так или иначе?
1 ответ
Каждый программист Go встречается io.Reader
, Вот пример,
for {
// io.Reader
n, err := r.Read(buf[:cap(buf)])
buf = buf[:n]
if err != nil {
// handle error
}
// process buf
for i := 0; i < len(buf); i++ {
// process byte
}
}
Как видите, возвращается количество фактически прочитанных байтов, поэтому мы корректируем размер буфера. Затем мы можем использовать len(buf)
для количества байтов для обработки.
Go не имеет C-подобных строк с нулевым символом в конце. Строка Go s
имеет длину len(s)
,
Не каждый тип имеет nil
значение. nil
полезно только с указателями типов. Ваш пример не работает.
var reply *[]string
for i := 0; i < n; i++ {
// invalid operation: (*reply)[i] == nil (mismatched types string and nil)
if (*reply)[i] == nil {
break // or continue
}
}