Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

go compile errors: undefined variables

Tags:

variables

go

new to programming / even newer to go. having trouble with a small go program - will not compile with undefined variable errors. the code:

package main

import (
  "fmt"
  "io"
  "os"
)

const file = "readfile.txt" 
var s string

func lookup(string) (string, string, string) {
    artist := s
    album := s
    year := s

    return artist, album, year
}

func enterdisk() (string, string, string) {
  var artist string
    var album string
    var year string

    println("enter artist:")
  fmt.Scanf("%s", &artist)

    println("enter album:")
  fmt.Scanf("%s", &album)

    println("enter year:")
  fmt.Scanf("%s", &year)

    return artist, album, year
}

func main() {

  println("enter UPC or [manual] to enter information manually:")
  fmt.Scanf("%s", &s)

    s := s
  switch s { 
        case "manual\n": artist, album, year := enterdisk()
        default: artist, album, year := lookup(s)
  }

    f,_ := os.OpenFile(file, os.O_APPEND|os.O_RDWR, 0666) 
  io.WriteString(f, (artist + ", \"" + album + "\" - " + year + "\n")) 

    f.Close()
    println("wrote data to file")
}

and the errors:

catalog.go:49: undefined: artist
catalog.go:49: undefined: album
catalog.go:49: undefined: year

however, those variables will not be defined until the code runs. additionally, the "lookup" function is not yet written, which it just returns what it is passed. i know the lookup and enterdisk functions work on their own, but i am trying to test the switch statement.

i have tried declaring the variables in main, however i get this error:

catalog.go:49: artist declared and not used
catalog.go:49: album declared and not used
catalog.go:49: year declared and not used

p.s. i have read http://tip.goneat.org/doc/go_faq.html#unused_variables_and_imports , and i agree that if this is only semantics, i still want to fix it. i just don't know how!

like image 941
rick Avatar asked Sep 07 '11 05:09

rick


2 Answers

Read about blocks and declarations and scope in Go.

Each clause in a switch or select statement acts as an implicit block.

Blocks nest and influence scoping.

The scope of a declared identifier is the extent of source text in which the identifier denotes the specified constant, type, variable, function, or package.

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.

switch s { 
    case "manual\n": artist, album, year := enterdisk()
    default: artist, album, year := lookup(s)
}
. . .
io.WriteString(f, (artist + ", \"" + album + "\" - " + year + "\n")) 

The scope of the short variable declarations of the artist, album, and year variables in the switch case and default case clauses begins and ends within each clause (the innermost containing block). The artist, album, and year variables no longer exist and are not visible to the WriteString() statement.

Instead, write:

var artist, album, year string
switch s {
case "manual\n":
    artist, album, year = enterdisk()
default:
    artist, album, year = lookup(s)
}
. . .
io.WriteString(f, (artist + ", \"" + album + "\" - " + year + "\n"))

Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared in the same block 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.

Therefore, the artist, album, and year variables are no longer declared (and assigned) using short variable declarations inside the switch case clauses because that would hide the variable declarations in the outer block, they are merely assigned.

like image 56
peterSO Avatar answered Oct 12 '22 23:10

peterSO


When you have variables being assigned conditionally, you must declare them before the conditions. So instead of:

switch s { 
    case "manual\n": artist, album, year := enterdisk()
    default: artist, album, year := lookup(s)
}

...try this:

var artist, album, year string

switch s { 
    case "manual\n": artist, album, year = enterdisk()
    default: artist, album, year = lookup(s)
}

(even though you have set a default, the compiler doesn't like that they are not declared first. Or maybe it doesn't like that they are declared twice, one in each condition, I'm not sure)

You see, now first we declare the variables, and inside the switch condition their values are set. The general rule is: if you are going to use the variables outside of the if/switch/for, declare them first to make them accessible in the scope they will be used.

like image 39
moraes Avatar answered Oct 12 '22 22:10

moraes