1
votes

This code:

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, playground")

    var a bool
    var b interface{}
    b = true
    if a, ok := b.(bool); !ok {
        fmt.Println("Problem!")
    }
}

Yields this error in the golang playground:

tmp/sandbox791966413/main.go:11:10: a declared and not used
tmp/sandbox791966413/main.go:14:21: a declared and not used

This is confusing because of what we read in the short variable declaration golang docs:

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. As a consequence, redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original.

So, my questions:

  1. Why can't I redeclare the variable in the code snippet above?
  2. Supposing I really can't, what I'd really like to do is find a way to populate variables with the output of functions while checking the error in a more concise way. So is there any way to improve on the following form for getting a value out of an error-able function?

    var A RealType
    if newA, err := SomeFunc(); err != nil {
        return err
    } else {
        A = newA
    }   
    
3

3 Answers

6
votes

This is happening because you are using the short variable declaration in an if initialization statement, which introduces a new scope.

Rather than this, where a is a new variable that shadows the existing one:

if a, ok := b.(bool); !ok {
    fmt.Println("Problem!")
}

you could do this, where a is redeclared:

a, ok := b.(bool)
if !ok {
    fmt.Println("Problem!")
}

This works because ok is a new variable, so you can redeclare a and the passage you quoted is in effect.

Similarly, your second code snippet could be written as:

A, err := SomeFunc()
if err != nil {
    return err
}
2
votes

You did redeclare the variable, that is the problem. When you redeclare a variable, it is a different variable. This is known as "shadowing".

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, playground")

    // original a.
    var a bool
    var b interface{}
    b = true
    // redeclared a here. This is a a'
    if a, ok := b.(bool); !ok {
        // a' will last until the end of this block
        fmt.Println("Problem!")
    }
    // a' is gone. So using a here would get the original a.
}

As for your second question. That code looks great. I would probably switch it to if err == nil (and swap the if and else blocks). But that is a style thing.

0
votes

The error raised by the compiler is saying that both declarations of variable a are not being used. You're actually declaring a twice, when using short declaration in the if condition you're creating a new scope that shadows the previous declaration of the variable.

The actual problem you're facing is that you're never using the variable value which, in Go, is considered a compile time error.


Regarding your second question, I think that the shortest way to get the value and check the error is to do something similar to this:

func main() {
    a, ok := someFunction()
    if !ok {
        fmt.Println("Problem!")
    }
}