Switch case statement falls through to default - go

I am new to go and can't figure out why the last case clauses (connect and test) fall through to default. But the ones with the new line characters (exit\r\n and connect\r\n) don't
There is no fallthrough statement.
I've tried labeling the switch and calling break [lbl] but the default block still gets executed
package main
import (
"fmt"
"strings"
"bufio"
"os"
)
func main() {
var cmd string
bio := bufio.NewReader(os.Stdin)
fmt.Println("Hello")
proceed := true
for proceed {
fmt.Print(">> ")
cmd, _ = bio.ReadString('\n')
cmds := strings.Split(cmd, " ")
for i := range cmds{
switch cmds[i]{
case "exit\r\n" :
proceed = false
case "connect\r\n":
fmt.Println("The connect command requires more input")
case "connect":
if i + 2 >= len(cmds) {
fmt.Println("Connect command usage: connect host port")
} else {
i++
constring := cmds[i]
i++
port := cmds[i]
con(constring, port)
}
fmt.Println("dont print anything else, dont fall through to default. There should be no reason why the default caluse is executed???")
case "test":
fmt.Println("dont print anything else, dont fall through to default. There should be no reason why the default caluse is executed???")
default:
fmt.Println("Unrecognised command: " + cmds[i])
}
}
}
}
func con (conStr, port string){
panic (conStr)
}

The Go Programming Language Specification
Switch statements
"Switch" statements provide multi-way execution. An expression or type
specifier is compared to the "cases" inside
Expression switches
In an expression switch, the switch expression is evaluated and the
case expressions, which need not be constants, are evaluated
left-to-right and top-to-bottom; the first one that equals the switch
expression triggers execution of the statements of the associated
case; the other cases are skipped. If no case matches and there is a
"default" case, its statements are executed. There can be at most one
default case and it may appear anywhere in the "switch" statement. A
missing switch expression is equivalent to the boolean value true.
ExprSwitchStmt = "switch" [ SimpleStmt ";" ] [ Expression ] "{" { ExprCaseClause } "}" .
ExprCaseClause = ExprSwitchCase ":" StatementList .
ExprSwitchCase = "case" ExpressionList | "default" .
The last switch case clauses ("connect" and "test") do not fall through to the default case clause. A break statement in a switch statement case clause breaks out of the switch statement; it does not break out of a surrounding for clause.
You have not provided us with a reproducible example: How to create a Minimal, Complete, and Verifiable example.. For example, you haven't shown us your input and output.
Here's an example, which is working as expected. There is a reason that the default clause is executed.
>> test 127.0.0.1 8080
dont print anything else, dont fall through to default. There should be no reason why the default caluse is executed???
Unrecognised command: 127.0.0.1
Unrecognised command: 8080
>>
The value of cmds, fmt.Printf("%q\n", cmds), is ["test" "127.0.0.1" "8080\r\n"].
Your program logic is badly flawed.

Try wrapping the subject of your switch statement with strings.Trim() like so:
switch strings.TrimSpace(cmds[i]) {
// your cases
}
In general though, it looks like the inner for loop is the wrong construct to be using in this case. Based on this snippet of code you probably want to remove that and just have the first element of the cmds array be the subject of your switch statement

Related

Golang Sprintf formatting a string and using it multiple times

I try to generate a sql query using Sprintf() where I have to use the same variable two times
myStr := "test"
str := Sprintf("SELECT ... WHERE a = '%#[1]s' or b = '%#[1]s'", myStr)
fmt.Println(str)
This snippets outputs the expected string
SELECT ... WHERE a = 'test' or b = 'test'
but go vet says:
unrecognized printf flag for verb 's': '#' (vet)
And I am puzzled why. Switching the printf verb to v satisfies go vet but adds " around my string. And I honestly doesn't see a mistake in using %#[1]s.
Any thoughts?
Using printf to construct queries is a bad idea, it opens you up to SQL injection.
See named parameters in the sql package.
There is no # Sprintf flag for a string verb (the flag # is e.g. adding 0x for hex values: %#x). So remove it to make your go vet troubles disappear:
myStr := "test"
str := Sprintf("SELECT ... WHERE a = '%[1]s' or b = '%[1]s'", myStr)
fmt.Println(str)
But: If any part of your constructed query (myStr) comes from external input (i.e. user input), you really should follow Hein's advise and use named parameters.

Shorthand return

The following code generates a syntax error (unexpected ++ at end of statement) in Go 1.6 or 1.7:
package main
import "fmt"
var x int
func increment() int {
return x++ // not allowed
}
func main() {
fmt.Println( increment() )
}
Shouldn't this be permitted?
It's an error, because the ++ and -- in Go are statements, not expressions: Spec: IncDec Statements (and statements have no results that would be returned).
For reasoning, see Go FAQ: Why are ++ and -- statements and not expressions? And why postfix, not prefix?
Without pointer arithmetic, the convenience value of pre- and postfix increment operators drops. By removing them from the expression hierarchy altogether, expression syntax is simplified and the messy issues around order of evaluation of ++ and -- (consider f(i++) and p[i] = q[++i]) are eliminated as well. The simplification is significant. As for postfix vs. prefix, either would work fine but the postfix version is more traditional; insistence on prefix arose with the STL, a library for a language whose name contains, ironically, a postfix increment.
So the code you wrote can only be written as:
func increment() int {
x++
return x
}
And you have to call it without passing anything:
fmt.Println(increment())
Note that we would be tempted to still try to write it in one line using an assignment, e.g.:
func increment() int {
return x += 1 // Compile-time error!
}
But this also doesn't work in Go, because the assignment is also a statement, and thus you get a compile-time error:
syntax error: unexpected += at end of statement
The accepted solution is right that the OP's code does not work because in go increment/decrement(x++/x--) statements are expressions that don't return a value.
However the solution presented has a slightly different effect than the original request.
x++ would return the value of x then increment in C like syntax.
however the opposite would happen if you do it this way:
x++
return x
You can negate that issue by reducing your initial value by one or by using a defer statement as written here:
func incr() int {
defer func() { counter++ }()
return counter
}
https://play.golang.org/p/rOuAv7KFJQw

What does a golang for { ..block.. } without conditions do?

I'm a golang neophyte and I've come across a rather interesting control structure which doesn't follow the classical imperative for-loop construct. I've been unable to locate on documentation on the structure either. The following is the code in question:
for {
// read each incoming message
m, err := getMessage(ws)
if err != nil {
log.Fatal(err)
}
// see if we're mentioned
if m.Type == "message" && strings.HasPrefix(m.Text, "<#"+id+">") {
// if so try to parse if
ans := lookup(session, m.Text)
if len(ans)>0 {
// looks good, get the quote and reply with the result
go func(m Message) {
for _, def := range ans {
if len(def[1]) > 0 {
m.Text = "*" + def[0] + " " + def[1] + "*: " + def[2]
} else {
m.Text = "*" + def[0] + "*: " + def[2]
}
postMessage(ws, m)
}
}(m)
// NOTE: the Message object is copied, this is intentional
} else {
// huh?
m.Text = fmt.Sprintf("sorry, that does not compute\n")
postMessage(ws, m)
}
}
}
Does the loop construct just loop forever or is there an eventing system binding behind the scenes?
The Go Programming Language Specification
For statements
A "for" statement specifies repeated execution of a block. The
iteration is controlled by a condition, a "for" clause, or a "range"
clause.
ForStmt = "for" [ Condition | ForClause | RangeClause ] Block .
Condition = Expression .
In its simplest form, a "for" statement specifies the repeated
execution of a block as long as a boolean condition evaluates to true.
The condition is evaluated before each iteration. If the condition is
absent, it is equivalent to the boolean value true.
If the condition is absent, for example, for { ... }, it is equivalent to the boolean value true, for example for true { ... }. It is sometimes referred to as an infinite loop. Therefore, you will need another mechanism, such as break or return, to terminate the loop.
The documentation for the for statement is the The Go Programming Language Specification.
for without any additional statements is basically the same as while (true) in other languages, an infinite loop.

Why does adding parentheses in if condition results in compile error?

The following Go code runs OK:
package main
import "fmt"
func main() {
if j := 9; j > 0 {
fmt.Println(j)
}
}
But after adding parentheses in condition:
package main
import "fmt"
func main() {
if (j := 9; j > 0) {
fmt.Println(j)
}
}
There is compile error:
.\Hello.go:7: syntax error: unexpected :=, expecting )
.\Hello.go:11: syntax error: unexpected }
Why does the compiler complain about it?
The answer is not simply "because Go doesn't need parentheses"; see that the following example is a valid Go syntax:
j := 9
if (j > 0) {
fmt.Println(j)
}
Go Spec: If statements:
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
The difference between my example and yours is that my example only contains the Expression block. Expressions can be parenthesized as you want to (it will not be well formatted, but that is another question).
In your example you specified both the Simple statement and the Expression block. If you put the whole into parentheses, the compiler will try to interpret the whole as the Expression Block to which this does not qualify:
Expression = UnaryExpr | Expression binary_op UnaryExpr .
j > 0 is a valid expression, j := 9; j > 0 is not a valid expression.
Even j := 9 in itself is not an expression, it is a Short variable declaration. Moreover the simple assignment (e.g. j = 9) is not an expression in Go but a statement (Spec: Assignments). Note that assignment is usually an expression in other languages like C, Java etc.). This is the reason why for example the following code is also invalid:
x := 3
y := (x = 4)
Because that is how the Go syntax defines an if statement.
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt |
Block ) ] .
And from Effective Go:
Parentheses
Go needs fewer parentheses than C and Java: control
structures (if, for, switch) do not have parentheses in their syntax.
and:
Control structures
The control structures of Go are related to those of C but differ in
important ways. There is no do or while loop, only a slightly
generalized for; switch is more flexible; if and switch accept an
optional initialization statement like that of for; break and continue
statements take an optional label to identify what to break or
continue; and there are new control structures including a type switch
and a multiway communications multiplexer, select. The syntax is also
slightly different: there are no parentheses and the bodies must
always be brace-delimited.
(Emphasis added)

no-op/explicitly do nothing in go

I have a type method that mutates the type's fields. It takes no arguments and returns nothing. The bulk of the method is a switch block. I want to be able to "short-circuit" out of the switch block with a no-op. Before I refactored it into a type method, I would've just returned out of the function, but that's out. Removing the case would break the logic of the method--the default case mutates state, which I don't want to do if this case is matched. I need the equivalent of Python's pass, basically.
Code:
func (parser *Parser) endSectionName () {
state = parser.State
buffer = parser.buffer
results = parser.results
switch {
case state.HasFlag(IN_ESCAPED) {
// ???
}
case !inSection(state) {
return state, NotInSectionError
}
case !state.HasFlag(IN_SECTION_NAME) {
state.Reset()
return state, errors.New("Parsing error: Not in section name")
}
default {
state.RemoveFlag(IN_SECTION_NAME)
s := buffer.String()
results[s] = new(Section)
buffer.Reset()
return state, nil
}
}
}
Unlike in other languages, in Go the control flow breaks at each case of a switch statement, control doesn't flow into the next case unless it is explicitly "asked" for with the fallthrough statement.
And also a statement is not required after the case (it can be empty). See this example:
i := 3
switch i {
case 3:
case 0:
fmt.Println("Hello, playground")
}
It will print nothing even though i==3 and there is no statement after case 3.
Same as this:
i := 3
switch {
case i == 3:
case i == 0:
fmt.Println("Hello, playground")
}
Try it on the Go Playground.

Resources