Why am I getting an never ending loop when reading from a byte.Buffer - go

Currently I'm writing a program that is reading a buffer from bytes.Buffer. Its supposed to stop reading when it finds the character e. But when I was reading the buffer using a for loop I noticed something odd. When I put the byte reading as part of the for statement I get an infinity loop (example in go playground):
b := bytes.NewBuffer([]byte("uoiea"))
for v, _ := b.ReadByte(); v != 'e'; {
println("The value is " + string(v))
}
But if I removed it and put it inside the for loop, it doesn't (example in go playground):
b := bytes.NewBuffer([]byte("uoiea"))
for ;; {
v, _ := b.ReadByte()
println("The value is " + string(v))
if v == 'e'{
break
}
}
Does anyone know why is this? I find it that adding the break expression is a very ugly and error prone way to solve this.

Because your post statement of the for-loop is empty (you have only init statement), so you don't read next byte every iteration (v is always 'u').
Here is the fixed version:
b := bytes.NewBuffer([]byte("uoiea"))
for v, _ := b.ReadByte(); v != 'e'; v, _ = b.ReadByte() {
println("The value is " + string(v))
}
As mentioned in comments, it's also recommended to check the error to avoid infinite loop when there is no 'e' byte:
b := bytes.NewBuffer([]byte("uoiea"))
for v, e := b.ReadByte(); v != 'e' && e == nil; v, e = b.ReadByte() {
println("The value is " + string(v))
}
ReadBytes returns io.EOF error when buffer is empty.

You are only reading the buffer once, when you are entering the loop. So the value of v will always be 'u'. You could solve it by reading the next byte in for loop's post statement also:
for v, _ := b.ReadByte(); v != 'e'; v, _ = b.ReadByte() {
// This works as long as there is an 'e' in your buffer
// Otherwise this goes to infinite loop also, as you are discarding error
But your second example is actually better and less ugly way to do this. There's nothing wrong with using break in loops like this. Actually it's very idiomatic in Go to write Read() loops as conditionless for loops and break from the loop when appropriate (usually when you get an io.EOF error indicating you reached the end of whatever you are reading). It leads to code that is easier to read, especially when there are many conditions that should cause break. The idiomatic and preferred (IMHO) way to write the code would be this:
b := bytes.NewBuffer([]byte("uoiea"))
for {
v, err := b.ReadByte()
if err == io.EOF {
// End of buffer. Should always break here to avoid infinite loop.
break
}
if err != nil {
// Error other than io.EOF means something went wrong with reading.
// Should handle it appropriately. Here I'll just panic.
panic(err)
}
if v == 'e' {
break
}
println("The value is " + string(v))
}
Which is almost the same as your working example. Just with error checks. But the io.EOF error check especially is very important, otherwise you''ll be stuck in infinite loop if there is no 'e' in your buffer.

Related

golang copy function understanding

Hey guys I was playing around with some buffers and I just wrote some code to understand how Read() works
package main
import (
"bytes"
"fmt"
"io"
)
func main() {
tmp := make([]byte, 2)
data := []byte("HEL")
dataReader := bytes.NewReader(data)
dest := make([]byte, len(data))
for {
n, err := dataReader.Read(tmp)
fmt.Println(n)
fmt.Println(string(tmp))
dest = append(dest, tmp[:]...)
if err == io.EOF {
break
}
}
fmt.Println(string(dest))
}
output:
2 -> n
HE -> tmp[:]
1 -> n
LE -> tmp[:]
0 -> n
LE -> tmp[:]
HELELE -> dest
So I know the output is wrong and I should actually be doing temp[:n] to write the bytes, but looking at the output I realised that the tmp buffer does not get cleared on every iteration, also when n is 1 should'nt the contents of the buffer be EL, I mean L is getting prepended to tmp not appended. I took a look at Read function but couldn't understand. Can someone explain it to me.
In the first iteration, Read reads two bytes, and your program produces the HE output. In the second iteration, Read reads one byte into tmp. Now tmp[0] contains that byte, but tmp[1] still contains the E read during the first iteration. However, you append all of tmp to dest, getting HELE. The third time around, read reads 0 bytes, but you still append the LE in tmp to dest.
The correct version of your program would be:
for {
n, err := dataReader.Read(tmp)
fmt.Println(n)
fmt.Println(string(tmp))
dest = append(dest, tmp[:n]...)
if err == io.EOF {
break
}
}

Efficient way to read Mmap

I am using syscall to read a byte array out of mmap:
file, e := os.Open(path)
if e != nil {...}
defer file.Close()
fi, e := file.Stat()
if e != nil {...}
data, e := syscall.Mmap(int(file.Fd()), 0, int(fi.Size()), syscall.PROT_READ, syscall.MAP_SHARED)
if e != nil {...}
data is the binary array I need.
I am using || as a delimiter, so I can get slices by using bytes.Split:
slices := bytes.Split(data, []byte("||"))
for _, s := range slices {
str := string(s[:])
fmt.Println(str)
}
This works fine, and I also stored the total number of messages (its type is uint32 which takes 8 bytes) at the beginning of the mmap.
When a new message is written in, I can get the total number of messages by reading the first 8 bytes.
Assuming I have the number of messages as n, I still need to do the following to read the new message:
slices := bytes.Split(data, []byte("||"))
s := slices[n - 1]
str := string(s[:])
fmt.Println(str)
Is there a more efficient way to do this?

How to allocate empty CString?

The cFunctionCall populates b and I am able to get content of string into GO string. However, I think that my memory allocation (line #1) is not efficient.
b := C.CString(strings.Repeat(" ", 50))
defer C.free(unsafe.Pointer(b))
C.cFunctionCall(b, 50)
rs := C.GoString(b)
log.Printf("rs: '%v'\n", rs)
If you want it to be initialized without the extra allocation and copy from Go, you would need to implement the strings.Repeat function over a C string:
func emptyString(size int) *C.char {
p := C.malloc(C.size_t(size + 1))
pp := (*[1 << 30]byte)(p)
bp := copy(pp[:], " ")
for bp < size {
copy(pp[bp:], pp[:bp])
bp *= 2
}
pp[size] = 0
return (*C.char)(p)
}
If it doesn't need to be initialized, you can simply malloc/calloc the pointer yourself and pass it to your function.
b := C.malloc(50) // or 51 if the depending on what size your function is expecting
defer C.free(unsafe.Pointer(b))
C.cFunctionCall((*C.char)(b), 50)
Unless this is being called many times and actually poses a performance problem, use what you already have and reduce the amount of C code you have to deal with.

Golang Read text file and take a slice from one of the read in values

In my code below, I'm hoping to read a text file filled with a number 1-5 per line. I want it to scan the line and read one of values and see if its < 6 and perform an action. Unfortunately I'm unable to take a slice of the values, they only print as an array. Any advice on how i can fix my code please?
//This is the part of the program that will read from a text file named "file"
//To see what numbers were selected last time so the recipe for week two can be
//a completely new recipe group of 5
f, err := os.Open("file")
if err != nil {
fmt.Println(err)
}
for {
var z int
var n int
n, err = fmt.Fscanln(f, &z)
if n == 0 || err != nil {
break
}
fmt.Println("int z :", z)
}
Your code worked fine in my test. Likely the file is formatted slightly differently or is in a different location?
for {
var z int
var n int
n, err = fmt.Fscan(f, &z)
if n == 0 || err != nil {
break
}
fmt.Println("int z :", z)
}
really, a variation of this question:
Reading an integer from standard input in Golang

Misunderstanding the usage of := in Go

I was reading this doc and saw the following fragment:
The := syntax is shorthand for declaring and initializing a variable, e.g. for var f string = "short" in this case.
f := "short"
fmt.Println(f)
The point is: is it only for strings? Or is it dymanic enough to understand what datatype should it store?
And plus: isn't it the same of var f = "short"?
Of course it infers the obvious type(s) returned by the expression on the right side.
The specification gives those examples :
i, j := 0, 10
f := func() int { return 7 }
ch := make(chan int)
r, w := os.Pipe(fd) // os.Pipe() returns two values
_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate
Note that it's not dynamic : everything happens at compile time, the type(s) being given by the right part expression.

Resources