为什么Go认为我没有使用声明的变量?

huangapple go评论83阅读模式
英文:

Why does Go think I am not using declared variable?

问题

我是你的中文翻译助手,以下是翻译好的内容:

我刚开始学习Go语言,想知道为什么Go认为我没有使用vpcGrp变量?你可以如何编写这段代码?

这是我的代码:

var vpcGrp *ec2.SecurityGroup
grpExists := false
resp, err := svc.DescribeSecurityGroups(params)
if err != nil {
    log.Error(err)
} else {
    for _, v := range resp.SecurityGroups {
        if *v.GroupName == grpName {
            log.Debug("找到VPC安全组[", grpName, "]")
            vpcGrp = v
            grpExists = true
        }
    }
}

if !grpExists {
    vpcGrp, err := createDbSecurityGrp(grpName, vpcId, region)
    if err != nil {
        log.Error(err)
        return nil, err
    }
}

return vpcGrp, nil
英文:

I am new to Go and wondering why does Go think I am not using vpcGrp? How would you code this?

Here is my code:

var vpcGrp *ec2.SecurityGroup
grpExists := false
resp, err := svc.DescribeSecurityGroups(params)
if err != nil {
	log.Error(err)
} else {
	for _, v := range resp.SecurityGroups {
		if *v.GroupName == grpName {
			log.Debug("VPC Security Group Found [", grpName, "]")
			vpcGrp = v
			grpExists = true
		}
	}
}

if !grpExists {
	vpcGrp, err := createDbSecurityGrp(grpName, vpcId, region)
	if err != nil {
		log.Error(err)
		return nil, err
	}
}

return vpcGrp, nil

答案1

得分: 7

《Go编程语言规范》中提到了块(Blocks)的概念。块是由匹配的大括号括起来的可能为空的声明和语句序列。

除了源代码中的显式块外,还有隐式块:

  • 宇宙块(universe block)包含所有的Go源代码。
  • 每个包都有一个包块(package block),包含该包的所有Go源代码。
  • 每个文件都有一个文件块(file block),包含该文件中的所有Go源代码。
  • 每个 "if"、"for" 和 "switch" 语句都被视为自己的隐式块。
  • "switch" 或 "select" 语句中的每个子句都作为一个隐式块。

块可以嵌套并影响作用域。

声明和作用域部分介绍了声明将非空标识符绑定到常量、类型、变量、函数、标签或包的概念。程序中的每个标识符都必须声明。同一个块中不能声明两次同一个标识符,也不能在文件块和包块中同时声明同一个标识符。

空白标识符可以像其他标识符一样在声明中使用,但它不引入绑定,因此不被声明。在包块中,标识符 "init" 只能用于 init 函数声明,与空白标识符一样,它不引入新的绑定。

作用域是指标识符所指定的常量、类型、变量、函数、标签或包在源代码中的范围。

Go使用块进行词法作用域:

  • 预声明标识符的作用域是宇宙块。
  • 在顶层(任何函数之外)声明的常量、类型、变量或函数(但不包括方法)的作用域是包块。
  • 导入包的包名的作用域是包含导入声明的文件块。
  • 方法接收器、函数参数或结果变量的作用域是函数体。
  • 在函数内部声明的常量或变量标识符的作用域从 ConstSpec 或 VarSpec(对于短变量声明为 ShortVarDecl)的结束位置开始,直到最内层包含块的结束位置。
  • 在函数内部声明的类型标识符的作用域从 TypeSpec 中的标识符开始,直到最内层包含块的结束位置。

在一个块中声明的标识符可以在内部块中重新声明。在内部声明的标识符在作用域内时,它表示内部声明所声明的实体。

短变量声明(Short variable declarations)是一种简化的变量声明形式,它使用以下语法:

短变量声明 = 标识符列表 ":=" 表达式列表。

它是一个没有类型的常规变量声明的简写形式:

"var" 标识符列表 = 表达式列表。

短变量声明只能出现在函数内部。在某些上下文中,比如 "if"、"for" 或 "switch" 语句的初始化器中,可以使用短变量声明来声明局部临时变量。

给出的代码示例中,"if" 语句和内部的 "for" 语句被视为各自的隐式块。在块中声明的标识符可以在内部块中重新声明。由于 "vpcGrp" 和 "err" 已经在外部作用域中声明过了,可以尝试使用赋值语句来更新它们的值:

vpcGrp, err = createDbSecurityGrp(grpName, vpcId, region)

这样就可以更新这两个变量的值了。

更多详细信息可以参考《Go编程语言规范》中的相关章节。

英文:

> The Go Programming Language Specification
>
> Blocks
>
> A block is a possibly empty sequence of declarations and statements
> within matching brace brackets.
>
> Block = "{" StatementList "}" .
> StatementList = { Statement ";" } .
>
> In addition to explicit blocks in the source code, there are implicit
> blocks:
>
> * The universe block encompasses all Go source text.
>
> * Each package has a package block containing all Go source text for that package.
>
> * Each file has a file block containing all Go source text in that file.
>
> * Each "if", "for", and "switch" statement is considered to be in its own implicit block.
>
> * Each clause in a "switch" or "select" statement acts as an implicit block.
>
> Blocks nest and influence scoping.
>
> Declarations and scope
>
> A declaration binds a non-blank identifier to a constant, type,
> variable, function, label, or package. Every identifier in a program
> must be declared. No identifier may be declared twice in the same
> block, and no identifier may be declared in both the file and package
> block.
>
> The blank identifier may be used like any other identifier in a
> declaration, but it does not introduce a binding and thus is not
> declared. In the package block, the identifier init may only be used
> for init function declarations, and like the blank identifier it does
> not introduce a new binding.
>
> Declaration = ConstDecl | TypeDecl | VarDecl .
> TopLevelDecl = Declaration | FunctionDecl | MethodDecl .
>
> The scope of a declared identifier is the extent of source text in
> which the identifier denotes the specified constant, type, variable,
> function, label, or package.
>
> Go is lexically scoped using blocks:
>
> * The scope of a predeclared identifier is the universe block.
> * The scope of an identifier denoting a constant, type, variable, or function (but not method) declared at top level (outside any function)
> is the package block.
> * The scope of the package name of an imported package is the file block of the file containing the import declaration.
> * The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
> * 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.
> * The scope of a type identifier declared inside a function begins at the identifier in the TypeSpec and ends at the end of the innermost
> containing block.
>
> An identifier declared in a block may be redeclared in an inner block.
> While the identifier of the inner declaration is in scope, it denotes
> the entity declared by the inner declaration.
>
> Short variable declarations
>
> A short variable declaration uses the syntax:
>
> ShortVarDecl = IdentifierList ":=" ExpressionList .
>
> It is shorthand for a regular variable declaration with initializer
> expressions but no types:
>
> "var" IdentifierList = ExpressionList .
>
> Short variable declarations may appear only inside functions. In some
> contexts such as the initializers for "if", "for", or "switch"
> statements, they can be used to declare local temporary variables.

Each "if", "for", and "switch" statement is considered to be in its own implicit block.

An identifier declared in a block may be redeclared in an inner block. While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration.

In some contexts such as the initializers for "if", "for", or "switch" statements, short variable declarations can be used to declare local temporary variables.

if !grpExists {
    vpcGrp, err := createDbSecurityGrp(grpName, vpcId, region)
    if err != nil {
        log.Error(err)
        return nil, err
    }
}

vpcGrp is a local variable that is set but not read; it's not used. err is a local variable that is both set and read; it's used.

Since vpcGrp and err have already been declared in an outer scope, try

 vpcGrp, err = createDbSecurityGrp(grpName, vpcId, region)

huangapple
  • 本文由 发表于 2016年3月10日 06:16:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/35903780.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定