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

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)

Related

I have been trying to print out this code, and it keeps popping out an error [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 months ago.
Improve this question
I've been trying to print this out, but keeps popping out an error message..
package main
import "fmt"
func main() {
for i:= 1; i<= 100; i++
switch i {
case i % 15 == 0:
fmt.Println("FizzyBuzz")
case i % 3 == 0:
fmt.Println("Fizzy")
case i % 5 == 0:
fmt.Println("Buzz")
default :
fmt.Println(i)
}
}
This is the code.
There are two issues with your code.
First of all, the for statement is missing its opening and closing curly brackets.
Then, the usage of the switch statement is wrong. You are, in fact, supposed to specify a value for the i variable for each of the cases that you want to evaluate. If you want to evaluate conditions (for example, i % 15 == 0), the if-else statement will be the right choice.
The code would then be like as follows:
package main
import "fmt"
func main() {
for i:= 1; i<= 100; i++ {
if i % 15 == 0 {
fmt.Println("FizzyBuzz")
} else if i % 3 == 0 {
fmt.Println("Buzz")
} else if i % 5 == 0 {
fmt.Println("Buzz")
} else {
fmt.Println(i)
}
}
}
You are trying to add a bool values to the case statements, the case statements expects a value wit with the same type as the comparison variable at the switch statement [ Here you passed i, which is integer ] and you passed a boolean to the case statements. I would recommend to use if else here instead of switch case.
Please checkout this link for more information about switch case statement in Golang here

Syntax rule for opening brace in Go for-loop

Case 1
This program compiles successfully:
package main
import (
"fmt"
)
func main() {
i := 0
for ; i < 3; i++ {
fmt.Println(i)
}
}
Case 2
But this does not:
package main
import (
"fmt"
)
func main() {
i := 0
for ; i < 3; i++
{
fmt.Println(i)
}
}
This leads to error:
./prog.go:9:18: syntax error: unexpected newline, expecting { after for clause
Case 3
But this compiles successfully:
package main
import (
"fmt"
)
func main() {
i := 0
for
{
fmt.Println(i)
}
}
Question
Why is it that in case 2, the opening brace for for is not allowed in the next line but in case 3 it is allowed?
In short, when you have this in line:
for ; i < 3; i++
a semicolon will be inserted automatically, resulting in syntax error.
Spec: Semicolons:
When the input is broken into tokens, a semicolon is automatically inserted into the token stream immediately after a line's final token if that token is
an identifier
an integer, floating-point, imaginary, rune, or string literal
one of the keywords break, continue, fallthrough, or return
one of the operators and punctuation ++, --, ), ], or }
So in Case 2 the lexer will automatically insert a semicolon at the end of the line which when present will "render" the code syntactically incorrect.
Not in Case 3 when there is only a for in a line, no semicolon is inserted (as per the quoted rules above, semicolon is only inserted after the break, continue, fallthrough and return keywords). So in Case 3 the code will not be extended with a semicolon and will remain syntactically correct.
For more details, see How to break a long line of code in Golang?
package main
import (
"fmt"
)
func main() {
i := 0
for ; i < 3; i++{
fmt.Println(i)
}
}
works its just that putting { in a new line causes the error you get.
in case 3 you don't have any statement to evaluate, so new line doesn't cause an y problem.

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

Switch case statement falls through to default

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

Go golang, syntax error: unexpected ++, expecting :

func test(args ...string) {
var msg map[string] interface{}
i := 0
msg["product"] = args[i++]
msg["key"] = args[i++]
msg["signature"] = args[i++]
msg["string_to_sign"] = args[i++]
}
go build utils.go
after compile, I get the error message
./utils.go:28: syntax error: unexpected ++, expecting :
./utils.go:28: missing statement after label
./utils.go:29: syntax error: unexpected ++, expecting :
./utils.go:30: syntax error: unexpected ++, expecting :
./utils.go:31: syntax error: unexpected ++, expecting :
./utils.go:36: syntax error: unexpected ++, expecting :
./utils.go:37: syntax error: unexpected ++, expecting :
why can't I put i++ in index of slice? is there any limitation in index of slice?
Go Frequently Asked Questions (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.
The Go Programming Language Specification
IncDec statements
The "++" and "--" statements increment or decrement their operands by
the untyped constant 1. As with an assignment, the operand must be
addressable or a map index expression.
IncDecStmt = Expression ( "++" | "--" ) .
The following assignment statements are semantically equivalent:
IncDec statement Assignment
x++ x += 1
x-- x -= 1
Write,
func test(args ...string) {
var msg map[string]interface{}
i := 0
msg["product"] = args[i]
i++
msg["key"] = args[i]
i++
msg["signature"] = args[i]
i++
msg["string_to_sign"] = args[i]
}
Which, in your particular case, simplifies to,
func test(args ...string) {
var msg map[string]interface{}
msg["product"] = args[0]
msg["key"] = args[1]
msg["signature"] = args[2]
msg["string_to_sign"] = args[3]
}
According to Language Specification, http://golang.org/ref/spec#IncDec_statements, i++ is a IncDec statements, which is a statement, but not a expression.As for args[index], index must be a expression. You want more details , just read it Go Language Specification, it's just what the language demand.
As other people have said i++ is a statement in go, not an expression as it is in C. Go has a different way of expressing the same intent using multiple assignment:
func test(args ...string) {
msg := make(map[string]string)
i := 0
msg["product"], i = args[i], i+1
msg["key"], i = args[i], i+1
msg["signature"], i = args[i], i+1
msg["string_to_sign"], i = args[i], i+1
fmt.Printf("%v\n", msg)
}
Your definition of map would have failed at runtime too.
++ operator is disappointing. This is my hack:
func test(args ...string) {
i := 0
inc := func(i *int) int { *i++; return i }
var msg map[string] interface{}
msg["product"] = args[inc(&i)]
msg["key"] = args[inc(&i)]
msg["signature"] = args[inc(&i)]
msg["string_to_sign"] = args[inc(&i)]
}

Resources