I want a set of code to be executed until user explicitly wants to exit the function. For eg: when a user runs the program, he will see 2 options:
Run again
Exit
this will be achieved using switch case structure. Here if user presses 1, set of functions associated with 1 will execute and if user presses 2, the program will exit. How should i achieve this scenario in golang ? In java, i believe this could be done using do while structure but go doesn't support do while loop. Following is my code which i tried but this goes in a infinite loop:
func sample() {
var i = 1
for i > 0 {
fmt.Println("Press 1 to run")
fmt.Println("Press 2 to exit")
var input string
inpt, _ := fmt.Scanln(&input)
switch inpt {
case 1:
fmt.Println("hi")
case 2:
os.Exit(2)
default:
fmt.Println("def")
}
}
}
The program irrespective of the input, prints only "hi". Could someone please correct me what wrong i am doing here ?
Thanks.
A do..while can more directly be emulated in Go with a for loop using a bool loop variable seeded with true.
for ok := true; ok; ok = EXPR { }
is more or less directly equivalent to
do { } while(EXPR)
So in your case:
var input int
for ok := true; ok; ok = (input != 2) {
n, err := fmt.Scanln(&input)
if n < 1 || err != nil {
fmt.Println("invalid input")
break
}
switch input {
case 1:
fmt.Println("hi")
case 2:
// Do nothing (we want to exit the loop)
// In a real program this could be cleanup
default:
fmt.Println("def")
}
}
Edit: Playground (with a dummied-out Stdin)
Though, admittedly, in this case it's probably overall clearer to just explicitly call (labelled) break, return, or os.Exit in the loop.
When this question was asked this was a better answer for this specific scenario (little did I know this would be the #1 result when searching Google for "do while loop golang"). For answering this question generically please see #LinearZoetrope's answer below.
Wrap your function in a for loop:
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println("Press 1 to run")
fmt.Println("Press 2 to exit")
for {
sample()
}
}
func sample() {
var input int
n, err := fmt.Scanln(&input)
if n < 1 || err != nil {
fmt.Println("invalid input")
return
}
switch input {
case 1:
fmt.Println("hi")
case 2:
os.Exit(2)
default:
fmt.Println("def")
}
}
A for loop without any declarations is equivalent to a while loop in other C-like languages. Check out the Effective Go documentation which covers the for loop.
The do...while in go can be this:
func main() {
var value int
for {
value++
fmt.Println(value)
if value%6 != 0 {
break
}
}
}
a while loop in Go can be as easy as this:
package main
import `fmt`
func main() {
for {
var number float64
fmt.Print(`insert an Integer eq or gr than 10!!!`)
fmt.Scanf(`%f`, &number)
if number >= 10 { break }
fmt.Println(`sorry the number is lower than 10....type again!!!`)
}
Conside to use "for-break" as "do-while".
foo.go
package main
import (
"fmt"
)
func main() {
i := 0
for {
i++
if i > 10 {
break
}
fmt.Printf("%v ", i)
}
fmt.Println()
}
shell
$ go run foo.go
1 2 3 4 5 6 7 8 9 10
Maybe not what you're looking for, but if you're trying to do something like this:
int i = 0;
while (i < 10) {
cout << "incrementing i now" << endl;
i++
}
cout << "done"
You'll have to do something like this in go:
var i = 0
fmt.Println(i)
for {
if i < 10 {
fmt.Println("incrementing i now")
i++
} else {
break
}
}
fmt.Println("done")
sum := 1
for sum < 1000 {
sum += sum
}
Explanation :
The basic for loop has three components separated by semicolons:
-the init statement: executed before the first iteration.
-the condition expression: evaluated before every iteration
-the post statement: executed at the end of every iteration
The init and post statements are optional.
So you can just put in the condition expression.
// While (CONDITION = true){
//code to execute ....}
//In go :
for CONDITION = true {
//code to execute}
This is one of the cleanest ways:
num := 10
for num > 0 {
// do stuff here
num--
}
Related
I have a problem with local variable "i". The second time i call nextEven, i think "i" should be intitialized back to 0. But the value "i" is saved in "makeEvengenerator()".
package main
import "fmt"
func makeEvengenerator() func() int {
i:=0
return func() (ret int) {
ret = i
i += 2
return ret
}
}
func main() {
nextEven := makeEvengenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())
}
I expected in to print out 0 0 0
Also I dont understand why everytime I call nextEven(), the code "i:=0" dont run again everytime i call the nextEven()
The second time i call nextEven, i think "i" should be intitialized back to 0
Why would it ? If you really want to reinitialize 0, then you can do:
func makeEvengenerator() func() int {
return func() (ret int) {
i := 0
ret = i
i += 2
return ret
}
}
But it would not make much sense as you usually want a closure to encapsulate a state or dependencies.
You can get some documentation and alternate examples here.
In Go, can a single line of input be read from stdin in a simple way, which also meets the following requirements?
can be called by disparate parts of a larger interactive application without having to create coupling between these different parts of the application (e.g. by passing a global bufio.Scanner between them)
works whether users are running an interactive terminal or using pre-scripted input
I'd like to modify an existing large Go application which currently creates a bufio.Scanner instance every time it asks users for a line of input. Multiple instances work fine when standard input is from a terminal, but when standard input is piped from another process, calls to Scan only succeed on the first instance of bufio.Scanner. Calls from all other instances fail.
Here's some toy code that demonstrates the problem:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// read with 1st scanner -> works for both piped stdin and terminal
scanner1 := readStdinLine(1)
// read with 2nd scanner -> fails for piped stdin, works for terminal
readStdinLine(2)
// read with 1st scanner -> prints line 2 for piped stdin, line 3 for terminal
readLine(scanner1, 3)
}
func readStdinLine(lineNum int64) (scanner *bufio.Scanner) {
scanner = readLine(bufio.NewScanner(os.Stdin), lineNum)
return
}
func readLine(scannerIn *bufio.Scanner, lineNum int64) (scanner *bufio.Scanner) {
scanner = scannerIn
scanned := scanner.Scan()
fmt.Printf("%d: ", lineNum)
if scanned {
fmt.Printf("Text=%s\n", scanner.Text())
return
}
if scanErr := scanner.Err(); scanErr != nil {
fmt.Printf("Error=%s\n", scanErr)
return
}
fmt.Println("EOF")
return
}
I build this as print_stdinand run interactively from a bash shell:
~$ ./print_stdin
ab
1: Text=ab
cd
2: Text=cd
ef
3: Text=ef
But if I pipe in the text, the second bufio.Scanner fails:
~$ echo "ab
> cd
> ef" | ./print_stdin
1: Text=ab
2: EOF
3: Text=cd
Your sequence is:
create scanner
wait read terminal
print result
repeat 1 to 3 (creating new scanner about stdin)
repeat 2 to 3
exit program
When you exec echo in pipeline, only exists a stdin/stdout file being read/write, but you are trying to use two.
UPDATE: The flow of execution for echo is:
read args
process args
write args in stdout
terminal read stdout and print its
See that this occur on press ENTER key. The argument whole is sent to echo program and not by line.
The echo utility writes its arguments to standard output, followed by
a . If there are no arguments, only the is written.
More here: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html.
See in source code how echo work:
while (argc > 0)
{
fputs (argv[0], stdout);//<-- send args to the same stdout
argc--;
argv++;
if (argc > 0)
putchar (' ');
}
So your code will work fine with this:
$ (n=1; while sleep 1; do echo a$n; n=$((n+1)); done) | ./print_stdin
$ 1: Text=a1
$ 2: Text=a2
$ 3: Text=a3
If you need repeat args in differents stdout, use "yes" program or alternatives.
yes program repeats the wrote args in stdout. More in:
https://git.savannah.gnu.org/cgit/coreutils.git/tree/src/yes.c
Example:
$ yes a | ./print_stdin
$ 1: Text=a
$ 2: Text=a
$ 3: Text=a
The suggestion in the comment by ThunderCat works.
The alternative to buffered read is reading a byte a time. Read single bytes until \n or some terminator is found and return the data up to that point.
Here's my implementation, heavily inspired by Scanner.Scan:
package lineio
import (
"errors"
"io"
)
const startBufSize = 4 * 1024
const maxBufSize = 64 * 1024
const maxConsecutiveEmptyReads = 100
var ErrTooLong = errors.New("lineio: line too long")
func ReadLine(r io.Reader) (string, error) {
lb := &lineBuf {r:r, buf: make([]byte, startBufSize)}
for {
lb.ReadByte()
if lb.err != nil || lb.TrimCrlf() {
return lb.GetResult()
}
}
}
type lineBuf struct {
r io.Reader
buf []byte
end int
err error
}
func (lb *lineBuf) ReadByte() {
if lb.EnsureBufSpace(); lb.err != nil {
return
}
for empties := 0; ; {
n := 0
if n, lb.err = lb.r.Read(lb.buf[lb.end:lb.end+1]); lb.err != nil {
return
}
if n > 0 {
lb.end++
return
}
empties++
if empties > maxConsecutiveEmptyReads {
lb.err = io.ErrNoProgress
return
}
}
}
func (lb *lineBuf) TrimCrlf() bool {
if !lb.EndsLf() {
return false
}
lb.end--
if lb.end > 0 && lb.buf[lb.end-1] == '\r' {
lb.end--
}
return true
}
func (lb *lineBuf) GetResult() (string, error) {
if lb.err != nil && lb.err != io.EOF {
return "", lb.err
}
return string(lb.buf[0:lb.end]), nil
}
func (lb *lineBuf) EndsLf() bool {
return lb.err == nil && lb.end > 0 && (lb.buf[lb.end-1] == '\n')
}
func (lb *lineBuf) EnsureBufSpace() {
if lb.end < len(lb.buf) {
return
}
newSize := len(lb.buf) * 2
if newSize > maxBufSize {
lb.err = ErrTooLong
return
}
newBuf := make([]byte, newSize)
copy(newBuf, lb.buf[0:lb.end])
lb.buf = newBuf
return
}
TESTING
Compiled lineio with go install and main (see below) with go build -o read_each_byte.
Tested scripted input:
$ seq 12 22 78 | ./read_each_byte
1: Text: "12"
2: Text: "34"
3: Text: "56"
Tested input from an interactive terminal:
$ ./read_each_byte
abc
1: Text: "abc"
123
2: Text: "123"
x\y"z
3: Text: "x\\y\"z"
Here's main:
package main
import (
"fmt"
"lineio"
"os"
)
func main() {
for i := 1; i <= 3; i++ {
text, _ := lineio.ReadLine(os.Stdin)
fmt.Printf("%d: Text: %q\n", i, text)
}
}
How can I make this simple for loop break after exactly one 1s has passed since its execution?
var i int
for {
i++
}
By checking the elapsed time since the start:
var i int
for start := time.Now(); time.Since(start) < time.Second; {
i++
}
Or using a "timeout" channel, acquired by calling time.After(). Use select to check if time is up, but you must add a default branch so it will be a non-blocking check. If time is up, break from the loop. Also very important to use a label and break from the for loop, else break will just break from the select and it will be an endless loop.
loop:
for timeout := time.After(time.Second); ; {
select {
case <-timeout:
break loop
default:
}
i++
}
Note: If the loop body also performs communication operations (like send or receive), using a timeout channel may be the only viable option! (You can list the timeout check and the loop's communication op in the same select.)
We may rewrite the timeout channel solution to not use a label:
for stay, timeout := true, time.After(time.Second); stay; {
i++
select {
case <-timeout:
stay = false
default:
}
}
Optimization
I know your loop is just an example, but if the loop is doing just a tiny bit of work, it is not worth checking the timeout in every iteration. We may rewrite the first solution to check timeout e.g. in every 10 iterations like this:
var i int
for start := time.Now(); ; {
if i % 10 == 0 {
if time.Since(start) > time.Second {
break
}
}
i++
}
We may choose an iteration number which is a multiple of 2, and then we may use bitmasks which is supposed to be even faster than remainder check:
var i int
for start := time.Now(); ; {
if i&0x0f == 0 { // Check in every 16th iteration
if time.Since(start) > time.Second {
break
}
}
i++
}
We may also calculate the end time once (when the loop must end), and then you just have to compare the current time to this:
var i int
for end := time.Now().Add(time.Second); ; {
if i&0x0f == 0 { // Check in every 16th iteration
if time.Now().After(end) {
break
}
}
i++
}
I know the question is a bit old, but below might be useful for someone looking for similar scenario:
func keepCheckingSomething() (bool, error) {
timeout := time.NewTimer(10 * time.Second)
ticker := time.NewTicker(500 * time.Millisecond)
defer timeout.Stop()
defer ticker.Stop()
// Keep trying until we're timed out or get a result/error
for {
select {
// Got a timeout! fail with a timeout error
case <-timeout:
// maybe, check for one last time
ok, err := checkSomething()
if !ok {
return false, errors.New("timed out")
}
return ok, err
// Got a tick, we should check on checkSomething()
case <-ticker:
ok, err := checkSomething()
if err != nil {
// We may return, or ignore the error
return false, err
// checkSomething() done! let's return
} else if ok {
return true, nil
}
// checkSomething() isn't done yet, but it didn't fail either, let's try again
}
}
}
This is my code written to implement a Stack. When I execute this, it generates some different kind of output totally. A screenshot of output is attached. Why is the program generating such invalid output? Is there any mistake in the code?
package main
import "fmt"
var st [100]int
var top int
func main() {
top = -1
ch := 0
temp := 0
for true {
fmt.Println("Enter you choice:")
fmt.Println("1. PUSH\n2. POP\n3. PRINT\n4. EXIT")
fmt.Scanf("%d", &ch)
switch ch {
case 1:
fmt.Println("Enter the value...")
fmt.Scanf("%d", &temp)
push(temp)
case 2:
temp = pop()
if temp != -1 {
fmt.Println("The popped value is ", temp)
}
case 3:
print()
case 4:
break
default:
fmt.Println("Please enter a valid choice")
}
}
}
func print() {
i := 0
if top == -1 {
fmt.Println("First insert elements into the stack")
} else {
fmt.Printf("The values are as follows")
for i <= top {
fmt.Println(st[i])
i++
}
}
}
func pop() int {
if top == -1 {
fmt.Println("Please push values before popping")
return -1
}
temp := st[top]
top--
return temp
}
func push(n int) {
top++
st[top] = n
}
Screen shot of the output:
The problem is that you want it to work like you enter a value and press Enter which generates a newline character, and you try to scan it using fmt.Scanf(). Quoting from its doc:
Newlines in the input must match newlines in the format.
So if you want to use fmt.Scanf(), the format string must include a newline \n. But since yours doesn't, the newline is not consumed, so the next line to read the value will automatically proceed.
Easy fix: add \n to the format string:
fmt.Println("Enter you choice:")
fmt.Println("1. PUSH\n2. POP\n3. PRINT\n4. EXIT")
fmt.Scanf("%d\n", &ch)
And:
fmt.Println("Enter the value...")
fmt.Scanf("%d\n", &temp)
An alternative is to simply use fmt.Scanln() which automatically parses a whole line:
fmt.Println("1. PUSH\n2. POP\n3. PRINT\n4. EXIT")
fmt.Scanln(&ch)
// ...
fmt.Println("Enter the value...")
fmt.Scanln(&temp)
Also, fmt.Scanf() and fmt.Scanln() return the number of successfully scanned values and an error. Be sure to check those to see if scanning succeeded.
Another error you have in your code is the Exit functionality: you used break statement in the case 4 branch. break will only break the switch and not the for! So use a return instead of break:
case 4:
return
Another fix could be to use labels, also note that for true { ... } is equivalent with for { ... } (you can omit the true):
mainloop:
for {
// ...
switch ch {
// ...
case 4:
break mainloop
// ...
}
}
Using Google Go, I'm trying to sync multiple threads performing an iterative filter on an image. My code basically works like outlined here:
func filter(src *image.Image, dest *image.Image, start, end, runs int, barrier ??) {
for i:= 0; i < runs; i++ {
// ... do image manipulation ...
// barrier.Await() would work here
if start == 1 {
// the first thread switches the images for the next iteration step
switchImgs(src, dest)
}
// barrier.Await() again
}
}
func main() {
//...
barrier := sync.BarrierNew(numberOfThreads)
for i := 0; i < numberOfThreads; i++ {
go filter(..., barrier)
}
The problem is that I would need a reusable barrier quite like Java's CyclicBarrier, setting the number of threads as its counter value. Unfortunately, the only implementation similar to a barrier I have found is sync.WaitGroup. The WaitGroup however cannot be reset atomically to it's previous counter value. It only offers a normal Wait() function that does not reset the counter value.
Is there any "Go idiomatic" way of achieving what I want or should I rather implement my own CyclicBarrier? Thanks a lot for your help!
You can use sync.Cond to implement CyclicBarrier, see source code of java's CyclicBarrier
Here is a minimized go version of CyclicBarrier (no timeout, no thread interrupts):
http://play.golang.org/p/5JSNTm0BLe
type CyclicBarrier struct {
generation int
count int
parties int
trip *sync.Cond
}
func (b *CyclicBarrier) nextGeneration() {
// signal completion of last generation
b.trip.Broadcast()
b.count = b.parties
// set up next generation
b.generation++
}
func (b *CyclicBarrier) Await() {
b.trip.L.Lock()
defer b.trip.L.Unlock()
generation := b.generation
b.count--
index := b.count
//println(index)
if index == 0 {
b.nextGeneration()
} else {
for generation == b.generation {
//wait for current generation complete
b.trip.Wait()
}
}
}
func NewCyclicBarrier(num int) *CyclicBarrier {
b := CyclicBarrier{}
b.count = num
b.parties = num
b.trip = sync.NewCond(&sync.Mutex{})
return &b
}
I don't fully understand how CyclicBarrier works, so excuse me if I'm way off.
A very simple wrapper around SyncGroup should do the job, for example:
type Barrier struct {
NumOfThreads int
wg sync.WaitGroup
}
func NewBarrier(num int) (b *Barrier) {
b = &Barrier{NumOfThreads: num}
b.wg.Add(num)
return
}
func (b *Barrier) Await() {
b.wg.Wait()
b.wg.Add(b.NumOfThreads)
}
func (b *Barrier) Done() {
b.wg.Done()
}
func filter(src *image.Image, dest *image.Image, start, end, runs int, barrier *Barrier) {
for i := 0; i < runs; i++ {
// ... do image manipulation ...
//this filter is done, say so by using b.Done()
b.Done()
b.Await()
if start == 1 {
// the first thread switches the images for the next iteration step
//switchImgs(src, dest)
}
b.Done()
b.Await()
}
}
func main() {
barrier := NewBarrier(5)
for i := 0; i < barrier.NumOfThreads; i++ {
go filter(1, barrier)
}
}