I have a situation where if something fails to assign a variable I instead assign it within a conditional statement however Go seems to think this variable is unused.
for index, value := range group.Values {
timestamp, err := time.Parse(time.RFC3339, value.Timestamp)
if err != nil {
strings.ReplaceAll(value.Timestamp, "+0000", "")
timestamp, err := time.Parse(time.RFC3339, value.Timestamp)
if err != nil {
log.Printf("Error parsing timestamp for point %s: (%s) %v", value.Context+"_"+value.ID, value.Timestamp, err)
continue
}
}
event := new(SplunkEvent)
event.Time = timestamp.Unix()
Go believes the variable timestamp inside the conditional statement is unused. Why is that? I have clearly used it directly after the condition.
The nested (inner) timestamp declaration shadows the outer one - so the outer one is never set. So since the inner value is never used, the compilation error is valid.
To fix, replace := declared assignment operator with = to (re)use the outer scope's timestamp (and err) values:
timestamp, err = time.Parse(time.RFC3339, value.Timestamp)
Related
Is A same as B?
A
if err := json.NewDecoder(r.Body).Decode(&t); err != nil {
rnd.JSON(w, http.StatusProcessing, err)
return
}
B
err := json.NewDecoder(r.Body).Decode(&t);
if err != nil {
rnd.JSON(w, http.StatusProcessing, err)
return
}
They are equivalent except one difference: the scope of the err variable. In the A version the scope of the err variable is the if statement: it's not accessible after the if.
In the B version the err variable will be in scope after the if statement too, and if err is already defined earlier, it could result in a compile-time error too.
It's good practice to always minimize the scope of variables (which gives you less chance to misuse them). If you do not wish to further examine the returned error after the if, it's better to use the A version. If you do need it after the if, then obviously the B version is the way to go.
I declare some variables (offsetI and limitI) outside of a conditional statement. Inside the conditional statement I am trying to assign them values, then use those values for a query after the conditional statement.
var (
number, size, offset, limit string
offsetI, limitI uint64
)
// Get the string values for number, size, offset, and limit
// ...
if size != "" {
// Parse the number value
numberI, err := strconv.ParseUint(number, 10, 64)
if err != nil {...}
// Parse the size value
limitI, err = strconv.ParseUint(size, 10, 64)
if err != nil {...}
// Calculate the offset
offsetI = numberI * limitI
} else {
// Parse the limit value
limitI, err := strconv.ParseUint(limit, 10, 64) // limitI declared and not used
if err != nil {...}
// Parse the offset value
offsetI, err = strconv.ParseUint(offset, 10, 64)
if err != nil {...}
}
// Make the query using offsetI and limitI
result, err := s.GetAllPaginated(offsetI, limitI)
if err != nil {...}
I am not intending to re-declare the limitI variable in the scope of the else statement, but I need to use the := operator for declaring a new err variable.
The only thing I could come up with was to separately declare another err variable, so I could use a regular assignment statement:
} else {
var err error // New
// Regular assignment statement now
limitI, err = strconv.ParseUint(limit, 10, 64)
if err != nil {...}
I would like to be able to do this without having to declare an additional error variable.
The extra var error is awkward, but it's a common way to address this situation. The spec on scoping says (emphasis mine):
The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
So in your case, that short variable declaration is declaring a different limitI scoped to the "innermost containing block." Since it only "lives" until the next closing brace, it isn't used.
In your specific case, an option might be to declare err outside the if/else, since it's used in both inner scopes, so you can use use = instead of := with those functions returning errors. Then there's no "inner limitI" declared and you have no unused variable issue.
"Shadowing" situations like this can also produce unexpected behavior rather than an error. go vet -shadow tries to detect "[v]ariables that may have been unintentionally shadowed" and, different but related, gordonklaus/ineffasign generalizes the "unused variable" check to detect useless assignments even if they weren't declarations.
The only thing I could come up with was to separately declare another err variable
This is being studied in the context of a future Go 2 (2019? 2020).
See "Error Handling — Problem Overview" (Russ Cox - August 27, 2018)
A possible proposed new syntax would avoid having to redeclare err:
Example:
func CopyFile(src, dst string) error {
handle err {
return fmt.Errorf("copy %s %s: %v", src, dst, err)
}
r := check os.Open(src)
defer r.Close()
w := check os.Create(dst)
handle err {
w.Close()
os.Remove(dst) // (only if a check fails)
}
check io.Copy(w, r)
check w.Close()
return nil
}
Note that go vet -shadow is no longer available since Go 1.12 (February 2019):
The experimental -shadow option is no longer available with go vet.
Checking for variable shadowing may now be done using
go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
go vet -vettool=$(which shadow)
I am trying to execute a SQL statement in the code below. However, sqlRes is unused and therefore cannot be compiled. I do not need the variable, but I need to declare it because Exec() returns multiple values.
How do I approach this?
stmt, err := db.Prepare("INSERT person SET name=?")
sqlRes, err := stmt.Exec(person.Name)
Replace sqlRes with the blank identifier (_). From the spec:
The blank identifier provides a way to ignore right-hand side values in an assignment:
_ = x // evaluate x but ignore it
x, _ = f() // evaluate f() but ignore second result value
Example:
stmt, err := db.Prepare("INSERT person SET name=?")
_, err = stmt.Exec(person.Name)
Another way to avoid the no new variables error is to wrap the check in an
if block:
if _, err := stmt.Exec(person.Name); err != nil {
panic(err)
}
https://golang.org/ref/spec#If_statements
As a Go "newb" I'm not sure why I'm receiving the errors undefined err and undefinded user in the console when compiling the program.
I have:
if req.Id == nil {
user, err := signup(C, c, &req)
} else {
user, err := update(C, c, &req)
}
if err != nil {
c.JSON(http.StatusOK, err)
return
}
doSomethingWith(user)
I realise I could probably declare the err and user variables before the conditional block but I would like to know why this doesn't work. Is it something to do with creating two new variables in one go?
UDPATE
Getting in a bit of a mess with this.
I've now got:
user := core.User{}
if req.Id == nil {
user, err := signup(C, c, &req)
} else {
user, err := update(C, c, &req)
}
cleanUser(&user)
and my errors now are user declared and not used. I'm not tackling the err part at the moment but I'm unsure why I'm getting errors about the user.
It's because the scope of the err variable you're creating: it is only in scope (and therefore valid/referable) till the end of innermost block in which you declared it.
Spec: Declarations and scope
The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
When you declare it before the if statement, then it will be in scope till the end of the container block which also includes the 2nd if where you test the err variable, so that is ok.
UDPATE:
Update to your update: you used a Short variable declaration which creates new variables because you used it in a new block. You haven't used these new variables (only the "other" user declared outside the inner block) hence the compile time error "user declared and not used".
Solution is simple: simply declare both variables before the if and don't use short variable declaration but simply assignment:
user := core.User{}
var err error
if req.Id == nil {
user, err = signup(C, c, &req)
} else {
user, err = update(C, c, &req)
}
if err == nil {
cleanUser(&user)
}
Or using one line to declare both user and err:
user, err := core.User{}, error(nil)
Is there an advantage to scoping the second err in an if statement after an err has already been created in the scope of foo()? Especially in terms of memory management or being idiomatic.
Version 1
func foo() {
temp, err := something()
if err != nil {
...
}
if err := other(); err != nil {
...
}
}
Version 2
func foo() {
temp, err := something()
if err != nil {
...
}
err = other()
if err != nil {
...
}
}
https://golang.org/doc/effective_go.html#control-structures
Remember, error is an interface. And nil interfaces are zero-length in bytes (and empty structs are zero-length too).
This means there is no additional work for the GC to cleanup either way.
It is a personal preference, and there's even a third way using named return values:
func foo() (err error) {
...
}
Though I highly recommend not using that pattern.
Personally, I prefer the idiomatic nature of inline with the if when I can and really enjoy when the pattern allows me to use it. But remember, the scoping of other variables are only available within the if:
if temp, err := other(); err != nil {
// can only use temp here
...
}
(unless you define the vars ahead of time, which defeats the purpose of inlining anyways)
But most often, I need to keep temp around after the evaluation:
temp, err := something()
if err != nil {
...
}
// continue to use temp
Which means most of my code looks like the above.
But when I run across a pattern that allows it, you bet I'll use it. For example, bufio's Writer.WriteByte:
if err := writer.WriteByte(b); err != nil {
...
}
Where writer and b were defined in the outer scope, most likely with their own err checks. There is zero point of defining err outside the scope of the evaluation.
Limiting the scope of the err value just seems like the idiomatic way, when you can use it.
Advantage of scoping variables:
Since it cannot be accessed from other scope, Data Integrity is preserved.
Only required data can be passed to function , thus protecting the remaining data
see this:
Where can we use Variable Scoping and Shadowing in Go?