14
votes

I cannot find the answer anywhere, so this is the situation:

// err has not yet been declared here
globalVar := "string"
if globalVar == "string" {
    globalVar, err := doSomethingWithString()
    if err != nil {
        // error handling
    }
}

That second globalVar declaration gives an error both then := and when '=' is used:

  • With := it says globalVar declared and not used because now globalVar is a new variable in the inner scope.
  • With = it says undefined err because it has not yet been declared.

So basically, there should be a way to define the difference between = and := for each variable on the left side of the declaration.

I see two possible solutions, which are both equally ugly in my opinion:

// err has not yet been declared here
globalVar := "string"
if globalVar == "string" {
    globalVar2, err := doSomethingWithString()
    if err != nil {
        // error handling
    }
    globalVar = globalVar2
}

or

globalVar := "string"
var err error
if globalVar == "string" {
    globalVar, err = doSomethingWithString()
    if err != nil {
        // error handling
    }
}

Do I have to use one of these work-arounds or is there a correct way of achieving what I need?

The second solution seems the least ugly, but if there are many variables you only need in the if-scope, these variables will not be removed after the scope and persist the whole outer scope. So the fist solution seems the best in my opinion.

But I'd like to hear how others resolve this situation...

1
In your second workaround (which actually is correct), you should replace err := errors.New("") with var err error. No need to create a new empty error, just let it be nil. - ANisus
Thanks, makes it a little bit cleaner already. But is that the most "correct" method for doing this? - Steven Roose
:= does what it says, which is declare and assign to new variables. You want it to act as := for part of the return values and = for the other, according to what has been declared before. Then, each := would be subject to analysis: does it declares and assigns or only assign? That would be inconsistent, imho. - JimPaek
That's the point I want to make. Sometimes you need both the = and := functionality in one statement. And that's as far as I know not possible. - Steven Roose
This is one of the open questions, see Golang issue and possibly other merged issues to that one. It seems there is no consensus how to remedy this, or if it should be done at all. - Gvozden

1 Answers

17
votes

Just don't use := in this case and predeclare both globalVar and err.

var (
    globalVar string
    err error
)

globalVar = "string"
if globalVar == "string" {
    globalVar, err = doSomethingWithString()
    if err != nil {
        // error handling
    }
}

or alternatively if you want to limit the scope of err:

globalVar := "string"
if globalVar == "string" {
    var err error
    globalVar, err = doSomethingWithString()
    if err != nil {
        // error handling
    }
}

http://play.golang.org/p/73bF_tHYsC for an example similar to the previous answer.

:= is meant as a convenience when you want to declare and assign in one statement. If it's getting in the way just don't use it.