I'm new to Go and I'm struggling with scope (as others).
The code below generates:
./excel.go:24: err declared and not used
./excel.go:25: sheet declared and not used
Why does this happen? I have declared both err
and sheet
in the parent scope, haven't I?
Excel.go:
package main
import (
"os"
"fmt"
"github.com/tealeg/xlsx"
)
func main() {
var file *xlsx.File
var sheet *xlsx.Sheet
var row *xlsx.Row
var cell *xlsx.Cell
var err error
fileName := "MyXLSXFile.xlsx"
if _, err := os.Stat(fileName); os.IsNotExist(err) {
fmt.Printf("File does not exist so create one");
file = xlsx.NewFile()
sheet, err = file.AddSheet("Sheet1")
} else {
fmt.Printf("File exists so open");
file, err := xlsx.OpenFile(fileName) // <-- line 24
sheet := file.Sheets[0] // <-- line 25
}
row = sheet.AddRow()
cell = row.AddCell()
cell.Value = "I am a cell!"
cell = row.AddCell()
cell.Value = "I am another cell!"
err = file.Save(fileName)
if err != nil {
fmt.Printf("help")
}
}
Use =
instead of :=
:
file, err = xlsx.OpenFile(fileName) // <-- line 24
sheet = file.Sheets[0] // <-- line 25
Go allows re-declaring variables with the same name in nested blocks. :=
declares a new variable. In your case both err
and sheet
are declared inside else block but are not used there.
TL;DR: Use =
for pure assignments. :=
declares a new variable.
sheet := file.Sheets[0]
declares a new variable within the scope of the else
block (see the chapter "Short variable declaration" from the language spec). This variable shadows the variable of the same name declared in the outer scope and will not exist in the outer scope (see the documentation):
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 the variable sheet
in line 25 and the variable sheet
in lines 12 and 28 are actually two different variables (with the first one declared in line 25 never being used after assignment).