Этикет длины буфера

У меня есть вопрос этикета. Я реализую 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
    }
}
Другие вопросы по тегам