Pulpcode

捕获,搅碎,拼接,吞咽

0%

聊聊作用域

最近在学习go语言,之前有C和python的经验,在学习go语言的时候,发现go有许多我喜欢的语言特性,今天这篇文章就从if的一个用法说起。

在go语言中,if接受初始化语句,通常用于设置一个(局部)变量。比如有如下两种写法:

1
2
3
4
5
6
7
8
9
// first
res := getSomething()
if res > 3{
dosomething()
}
// second
if res := getSomething(); res > 3{
dosomething()
}

为什么第二种更好?因为对于res这个变量本身,在用于if判断之后,再没有用了,所以应该把它的作用域限定,
这样的做法,一方面,像a,b,c, i,j,k, temp, res,这些常用的变量名,会被经常使用,所以应该限制他们的作用域,让他们更局部(如果英文不好,你会觉得起变量名是个令你头痛的事情。)

另一方面,可以防止这个变量名在之后的代码中被无意中使用到,就算没有错,也会降低程序的可读性,说到这方面的可读性,不仅仅是go语言提供给你这样在if内能初始化语句的机会,就算没有这样的语言特性,你也应该在一个变量要使用的时候,再去定义它,而不是一开始就把所有的变量定义完,

当然,在早期的c语言中,也就是K&R C中,并不像如今的C,或者是c++,可以在使用一个变量的时候,才去定义它,必须要在开头就全部定义好,这样,如果想查看某一个变量的时候,就必须在去程序的开头找,程序的可读性,明显下降了许多(所以前辈们写程序是很幸苦的)。

所以,在需要的时候才去声明,并限定其作用域,自然是个好办法。

在比如c99之前的for语言中,

1
2
3
4
5
6
7
8
for(int i=0; i!=10; i++)
{% endhighlight%}

这样的代码是不可以的,不能在for中设置这个局部变量,你必须要这样写

{% highlight c linenos %}
int i;
for( i=0; i!=10; i++)

显然,第一种方式,限定了i的作用域,这样更好,c99和c++就给你在for内设置局部变量的机会。

需要注意的是vc6.0 中,并不是标准的c++,所以对于在for内设置的局部变量,它能够“作用域外流”。
比如如下代码:

1
2
for(int i=0;i!=10;i++);//注意这里的分号
i = 5;

应该是错误的,但是在vc6.0下,却能运行,这样你在vc6.0下,写如下的代码就会报错说“重复定义i这个变量”。

1
2
3
4
5
6
7
8
9
for(int i=0;i!=10;i++)
{
doSomething();
}

for(int i=0;i!=10;i++)
{
doSomething();
}

小到代码之间,大到程序文件之间,作用域也很重要。在c语言中,头文件的include会让全局变量的作用域“扩散到”每个文件之间,这样很容易造成混乱,不过在c语言中可以把全局变量声明为static的,这样,全局变量的作用域就能被限制在文件中了。而在c++中,命名空间能很好的做到限定作用域。

但是许多c++初学者,却不重视命名空间,写c++程序,上来就:

1
using namespace std;

一下子就把命名空间全部暴露了,若是用cout,你可以这样么:

1
std::cout << "Hello,World" << std::endl;

如果你要写一个库,给别人用,那么一定不要在代码中把标准库或者第三方库的命名空间暴露,因为你并不知道,用户是否愿意这样做,所以,不要替用户做了。

当然,python 和 go语言的包机制,更加方便,

1
2
import os
os.system('/usr/bin/firefox')

这类命名空间或者包,所构成的库,不仅仅是为了重用,还有“作用域的思想”在里面。