文件私有的全局变量

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

Global variable private to file

问题

在GOLANG中,有没有一种方法可以使变量的作用域局限于包内的一个文件?

在我的情况下,有两个文件ex1.go和ex02.go。ex01.go定义了一个全局变量

var wg sync.WaitGroup

该变量在该文件中的多个函数中使用。

在另一个文件ex02.go中(与ex01.go没有关系,除了ex01.go和ex02.go都属于同一类问题 - 即并发),我无法定义一个与waitGroup相关的变量,如下所示:

var wg sync.WaitGroup

我会得到一个错误 - “变量名在此块中被重新声明”

有没有办法防止变量名溢出到其他文件中?

英文:

In GOLANG, Is there a way to make a variable's scope local to a file within a package?
In my case, there are 2 files ex1.go and ex02.go. ex01.go defines a global variable

var wg sync.WaitGroup

which is used across functions in that file.

In another file ex02.go (which has no relation with ex01.go except that both ex01.go and ex02.go belong to the same class of problems - i.e. concurrency), I can't define a variable for waitGroup as

var wg sync.WaitGroup

I get an error - "variable name is re-declared in this block"

Is there a way to keep the variable names from spilling over to the other files?

答案1

得分: 40

为了变量作用域的目的,在Go语言中,文件没有意义。将包中的所有文件视为被连接在一起,这在编译之前会发生(简化来说)。

这意味着:不,没有办法将变量的作用域限定在一个文件中。

如果你需要两个全局的WaitGroup,你需要将它们定义为独立的变量。

英文:

For the purpose of variable scoping, files have no meaning in Go. Think of all files in a package as if they would be concatenated, which (simplified) is exactly what happens before compilation.

That means: No, there is no way of scoping a variable to a file.

If you need two global WaitGroups, you need to define them as individual variables.

答案2

得分: 5

只有显式导入的标识符具有文件的作用域。比如在文件wg.go中,你定义了:

package wg
var Wg sync.WaitGroup
// and all staff common to class of problems - i.e. concurrency

然后你可以在文件ex1.go中这样写:

import wg
wg.Wg.Add(1) //在文件内部使用

在ex2.go中也是一样的。

英文:

Only explicitly imported identifiers have file's scope. Say in file wg.go you define

package wg
var Wg sync.WaitGroup
// and all staff common to class of problems - i.e. concurrency

and then you can in file ex1.go

import wg
wg.Wg.Add(1) //use locally to file

same in ex2.go

答案3

得分: 2

我建议将下面的信息应用到你具体的问题中。下面的大部分示例来自于这篇Medium文章

Go语言的变量声明和作用域有一些与其他语言一致的特点,也有一些更特别的特点。

与作用域和变量声明相关的一致特点是:如果你在一个块中声明了一个变量v,那么嵌套在这个块中的每个块都可以"看到"这个变量v。如果你在其中一个嵌套块中重新声明了v,那么当你离开这个内部块时,就会失去这个新值,恢复为旧值。

示例:

func main() {
    {
        v := 1
        {
            fmt.Println(v)
        }
        fmt.Println(v)
    }
    // 编译错误:"undefined: v"
    // fmt.Println(v)
}

// 输出:
// 1
// 1

在这个例子中,你可以看到变量的值在从声明处嵌套的作用域中是可见的。

v := 1
{
    v = 2  // 赋值
    fmt.Println(v)
}
fmt.Println(v)

// 输出:
// 2
// 2

这个例子进一步展示了,由于变量v是在外部作用域中声明的,我可以重新赋值(而不是重新声明)v的值,并且这个新值会在任何可以"看到"v的作用域中生效。

v := 1
{
    v := 2  // 短变量声明
    fmt.Println(v)
}
fmt.Println(v)

// 输出:
// 2
// 1

这个最后的例子更接近你的原始问题。它展示了我可以使用相同的变量名,在不同的作用域中进行多次声明,从而创建多个变量。这引出了更不同的特点。

与此相关的更不同的特点是Go语言的包私有和包公有声明以及顶层标识。

首先,让我们谈谈顶层标识。顶层标识是指在任何其他类型或函数声明之外声明变量、类型或函数。func main()就是一个顶层标识的很好例子。现在让我们想象一下Go包中的多个文件。可以将多个文件想象成连接在一起形成一个非常长的文件。有了这个想法,我们现在可以看到为什么没有文件私有变量的概念。只有包私有或包公有。

包私有的顶层变量只对包本身可见,对于可能导入该包的任何人来说是不可见的。包公有对整个包以及可能导入该包的任何人都是可见的。这仅仅通过名称的首字母大小写来表示。

// 包公有
func Main(){...}
var MyVar;
type MyType uint64;

// 包私有
func main(){...}
var myVar;
type myType uint64;

注意大小写是有区别的,main()Main()不会调用相同的函数。你也可以利用这一点来解决你的问题,但我不建议仅仅改变大小写来避免重新声明。

英文:

I recommend taking the information below and appropriately applying it to your specific problem. Most of the examples below are from This Medium article.

There are several characteristics of Go's variable declarations and scoping that are consistent with other languages and some that are more particular to Go.

The more consistent characteristics deal with blocks and variable declarations. If you declare a variable, v, in a block than every block nested to this can 'see' v. If you redeclare a inside one of these nested blocks then as you leave this inner block you lose that value to a and regain the old value.

examples:

func main() {
    {
        v := 1
        {
            fmt.Println(v)
        }
        fmt.Println(v)
    }
    // “undefined: v” compilation error
    // fmt.Println(v)
}

> ./bin/sandbox
1
1

In thise ^ example you can see that a variable's value is 'seen' down scopes nested from its declaration

v := 1
{
    v = 2  // assignment
    fmt.Println(v)
}
fmt.Println(v)

>./bin/sandbox
2
2

This example expands on that by saying that since the variable v was declared on the outer scope then I can also reassign, not redeclare, the value of v and have it take effect on any scope that can 'see' v.

v := 1
{
    v := 2  // short variable declaration
    fmt.Println(v)
}
fmt.Println(v)

>./bin/sandbox
2
1

This last example is closer to your original question. This one shows that I can have the same variable name but have multiple declarations with multiple variables depending on my scope. This leads us to the more different

The more different characteristics deal with Go's concept of package private and public declarations and top level identification.

First let's talk about top level identification. Top level identification is declaring a variable, type, or function outside of any other type or function declaration. func main() is a good example of a top level identification. Now let's think of multiple files in a Go package. One way to think of multiple files in a Go package is to think of them all appended together to make a really long file. With this in mind we can now see why there's no concept of file private variables. There is only package private or package public.

Package private are top level variables that are only visible to the package itself and are not visible to anyone that might import this package. Package public are visible to the entire package and anyone that might import this package. This is depicted solely by the capitalization of the first letter of the name.

// Package Public
func Main(){...}
var MyVar;
type MyType uint64;

// Package Private
func main(){...}
var myVar;
type myType uint64;

Notice that the case does matter and main() and Main() do not invoke the same function. You could also use this to solve your problem but I would not recommend just changing the capitalization just to get around the redeclaration.

huangapple
  • 本文由 发表于 2017年7月22日 19:18:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/45253939.html
匿名

发表评论

匿名网友

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

确定