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.
Related
the following is my function where im trying to Validate the ID's and unable to return values from the inner loop.
func Validate(id int, tn []Node) int {
var value int
for _, j := range tn {
if id == j.ID {
println(id, j.ID)
value = j.ID
println("aa", value)
break
} else {
if j.Children != nil {
ValidateID(id, j.Children)
}
}
}
return value
}
It looks like you want to return whether the ID was found in any node of a tree. Your code is almost there, but you need to check whether the recursive call finds it. Using return rather than break makes the code simpler.
I removed the print statements, which I guess are there for debugging purposes.
I also replaced the return value with a bool (the original code either returned the ID itself or 0 to represent not-found), and removed the j.Children == nil test (the code returns false for an empty slice:
// ValidateID reports whether id exists in a tree of nodes.
func ValidateID(id int, tn []Node) bool {
for _, j := range tn {
if id == j.ID || ValidateID(id, j.Children) {
return true
}
}
return false
}
Note if you want to actually return something other than a bool from the target node, I'd make the function return two values: that which you are interested and the bool that says whether the ID was found. Relying on sentinel values like 0 is discouraged by "Effective Go".
My golint returns this error message but i don't really understand what it means.
As in title:
return statements should not be cuddled if block has more than two lines (wsl)
my code is this:
func validateCountry(product models.Product, countries []models.Country) bool {
if !product.CountryCode.Valid {
return true
}
for _, country := range countries {
if country.Code == product.CountryCode.String {
return !country.Enabled && country.Deprecated
}
}
return false
}
What the linter does not like seems to be the last return false.
I'm very confused, i didn't setup the linter in this codebase, and i don't really know how to either skip this rules or how to fix it.
This error means that, in your case, you need to put a blank line before any next return statement:
[empty line] <-- need this
return true
...
[empty line] <-- need this
return !country.Enabled && country.Deprecated
should not be cuddled means there must be no code lines near the return statement.
In the slide #5 of the flow control Go Tour I don't understand how the return keyword is working inside the function sqrt().
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
I understand the code with a else clause like this
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}else{
return fmt.Sprint(math.Sqrt(x))
}
}
This code executes without problems, but the linter, golint, in VsCode complains about the else clause.
Does the statement return sqrt(-x) + "i" inside the first if block ends the execution of the function ?
how is it exactly working ?
As with most (if not all?) the first return statement the compiler hits will exit the function and not continue.
It's warning reported by go linter. Code underneath is valid.
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
This one below is also valid, but will generate some warning.
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
} else {
return fmt.Sprint(math.Sqrt(x))
}
}
Basically if there is if statement and the body contains return statement, better not to use else block.
The Go Programming Language Specification
Return statements
A "return" statement in a function F terminates the execution of F,
and optionally provides one or more result values. Any functions
deferred by F are executed before F returns to its caller.
The specification defines the language. return terminates the function.
Go Code Review Comments
Indent Error Flow
Try to keep the normal code path at a minimal indentation, and indent
the error handling, dealing with it first. This improves the
readability of the code by permitting visually scanning the normal
path quickly. For instance, don't write:
if err != nil {
// error handling
} else {
// normal code
}
Instead, write:
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
While either will work, as a matter of style, remove the unnecessary else and indentation. It's a similar to error flow indentation.
I am trying to make a for loop stop when a string contains a certain numeral. The only problem is it stops adding value to the string after adding 31 to the counter. I feel it is going to fast before it can play catch up. I know there's always another way to complete the task but I would just want to understand why it does this.
What I'm trying to accomplish is having the counter act as the height. The theSlice = 8 and webSlices is a list. The whole text says "Height is a 1" so I am trying to see what number is the height and make counter equal that.
Code:
func breakDownSlice(theSlice int, webSlices []string) {
counter := 0
done := false
for done == false {
log.Println(webSlices[theSlice])
log.Println(counter)
done = strings.Contains(webSlices[theSlice], string(counter))
if done == true {
log.Printf("The height is %d", counter)
} else {
counter++
}
}
}
the line
done = strings.Contains(webSlices[theSlice], string(counter))
string(counter) can't work here, use strconv.Itoa(counter) instead
Go has a common idiom that looks like this:
if val, err := func(); err != nil {
/* val and err are in scope */
...
}
/* val and err are no longer in scope */
using "short assignment". I'm certainly a fan. It feels similar to doing:
/* code not involving val */
{
int val;
if ((val = func()) == ERR_VALUE) {
/* Process the error */
}
/* Do something with val */
}
/* more code not involving val */
in C++. What trips me up is that, in the case where there is more than one variable in the first clause of the if, they have to have the same scope, i.e. you have to do either:
var err error
var val string
if val, err = func(); err != nil {
...
or
if val, err := func(); err != nil {
...
A very common use case would seem to be where you have a variable that you'd like to set in the first clause of the if, test for an error, and if there is none, continue with the rest of the program flow (and be able to use whatever values you assigned in executing the if). But, it seems to me, if you want to do that, you have to either:
Use a temporary variable, and then assign the persistent variable value inside an else:
var val
if tempval, err := func(); err != nil {
/* Process the error */
} else {
val = tempval
}
Declare the err variable with scope that extends past the if, as above.
The first option seems clunky - being forced to use an "else" clause just to make sure that the value doesn't fall out of scope - and the second throws away the advantages of limiting the scope of the variables. What idioms do more experienced Go programmers use for this (seemingly very common) situation?
The Go Programming Language Specification
If statements
"If" statements specify the conditional execution of two branches
according to the value of a boolean expression. If the expression
evaluates to true, the "if" branch is executed, otherwise, if present,
the "else" branch is executed.
IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .
.
if x > max {
x = max
}
The expression may be preceded by a simple statement, which executes
before the expression is evaluated.
if x := f(); x < y {
return x
} else if x > z {
return z
} else {
return y
}
If you can't take advantage of the special form,
if val, err := fnc(); err != nil {
// ...
}
then use the regular form,
val, err := fnc()
if err != nil {
// ...
}
The regular form is the Go language necessary and usual form. The special form is a specialization, for convenience, of the regular form; it's not necessary. If the special form is more convenient to use than the regular form, use it. Otherwise, use the regular form.
Go is a block-structured programming language tracing it's ancestry back to Algol 60, C, Pascal, Modula 2, and Oberon.
The Go Programming Language Specification
Blocks
Declarations and scope
Therefore, you can write
x := false
{
x := true
if x {
fmt.Println(x)
}
}
fmt.Println(x)
or, equivalently, as a convenience,
x := false
if x := true; x {
fmt.Println(x)
}
fmt.Println(x)
The output in both cases is
true
false