0

How do I to write a generic Go function to push bytes into a byte array?

I suppose appending to a slice is not a perfect fit, because the array should not grow. However the function should handle any array size. I am considering to slice the array just to make the function accept any array size. See my sketch below.

Is there a cleaner way?

Play: http://play.golang.org/p/Gii9-JM33E

func push(buf []byte, size int, b byte) (int, error) {
    max := len(buf)

    if max < 1 {
        return size, fmt.Errorf("buffer underflow: max=%d char=%d", max, b)
    }

    if size >= max {
        return size, fmt.Errorf("buffer overflow: size=%d max=%d char=%d", size, max, b)
    }

    buf[size] = b

    return size + 1, nil
}

Usage:

buf := [3]byte{}
size := 0
var err error
size, err = push(buf[:], size, 'a')
7
  • what's wrong with your current function? Commented May 30, 2014 at 14:42
  • @OneOfOne it requires the slicing of the array just to accept any array size. i feel it is clumsy to pass a slice plus its underlying array size... i hope there is a cleaner idiomatic way. Commented May 30, 2014 at 14:46
  • @JimB the array plus its size appear in the usage pattern i added below the function. Commented May 30, 2014 at 14:48
  • Ok, I see it. but why are you using an array in the first place? Commented May 30, 2014 at 14:50
  • 1
    I have the feeling you are focusing on the wrong thing here. What are you trying to solve ? Commented May 30, 2014 at 17:43

2 Answers 2

2

You almost certainly want to use a slice instead of an array. A slice has three things: an underlying backing array, a capacity, and a length. The capacity "cap" tells you the size of the underlying backing array.

So, you can use append after checking that len(s) < cap(s) to avoid any reallocation. Or if you want to make a function, perhaps something like this:

func pushByte(s []byte, b byte) ([]byte, error) {
    if len(s) == cap(s) {
        return s, errors.New("capacity reached")
    }
    return append(s, b), nil
}

You'd use it something like this:

s := make([]byte, 0, 10)
var err error
if s, err = pushByte(s, 10); err != nil {
    ... handle error
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I think your suggestion is indeed better.
1

The size of an array is part if its type.

If there's a set of sizes you know you are going to accept, you could take a buf interface{} with a type switch on the sizes you want. I would assume you know the array sizes, since they must be constant at compile time.

Other than that you would need to use reflection to actually find the array size, and store elements within the array.

It's very infrequent you need to use an array instead of a slice. You may want to reconsider why you have to pass arrays of varying sizes around.

1 Comment

I have few arrays sizes, and was worried about having some fixed-size types (say [200]byte, [1000]byte, [64000]byte) appearing multiple times in the code. From you answer I see it may be wiser to define some custom array types (as in type Buf1 [100]byte, type Buf2 [1000]byte, type Buf3 [64000]byte) or to only use slices and prevent them from growing (as suggested by @Anonymous).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.