不能在do/while循环中声明的while子句中使用变量

本文关键字:while 子句 变量 声明 循环 不能 do | 更新日期: 2023-09-27 18:10:38

为什么我不允许使用我在do内声明的变量,并在do/while循环的while部分内使用它?

do
{
   index += index;
   int composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); // cannot resolve symbol composite

第一次看到这个,我以为是编译器的bug。所以我重新启动了Visual Studio多次,但它仍然不识别while中的变量。

代码有什么问题,还是这是编译器的错误?

不能在do/while循环中声明的while子句中使用变量

你的变量是在do/while之外使用的(在c#中,通常是用括号定义范围),因为它是在do-while内部声明的,所以你不能在该范围之外使用它。

你可以通过简单地在循环外声明它来解决这个问题。

int composite = 0;   // you are not required to set it to zero, as long 
                     // as you do not use it before you initialize it
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); 

注意(1),通常的做法是一次声明和设置一个变量,但这不是必需的,只要你在使用它之前设置它。

注释(2):在c#中,花括号{....}定义了变量的作用域。你不能在它的作用域之外使用一个变量,它不再是"可见的",事实上,一旦它超出了作用域,它就准备被垃圾收集,它的内容可以是未定义的。


我知道这个,但是为什么编译器不能这样做

你在评论里问了这个问题。答案并没有看起来那么简单。这在很大程度上取决于语言的定义。有些语言,如Perl或较老的BASIC,允许在任何级别和任何范围内声明变量。其他语言允许变量的作用域,并要求在使用变量之前声明变量(c#, Java, c++, Python)。通常(但不一定),这在静态类型语言中很常见,因为编译器需要事先知道要在变量中放入什么类型的数据,以便进行类型检查

如果编译器强制声明,但不强制作用域,这意味着所有变量都是全局的,这在大型程序中很难做到,因为作为程序员,您必须维护在哪里使用了哪些变量名并保持唯一性。这非常乏味(想想COBOL)。

c#添加了dynamic关键字,它允许变量具有动态类型,但这仍然要求您在使用变量之前定义该变量。

编译器可以做到这一点,但是c#的设计者认为清晰的语言更好,在他们看来,声明变量是一件好事,因为它可以防止虚假错误和无法跟踪的代码:

// can you see the problem?
va1l = 1;
val1 = 2;
vall = va1l + vall;
强制您声明变量并使它们具有作用域,以防止这种错误和相关类型的错误。

这不是一个bug。while循环中的条件在定义变量的块之外。

int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite));

这个变量的作用域就在循环内部....不能在循环外使用

你应该这样做....

int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite)); 

{ ... }表示代码块时,该块中的所有变量都被限制在该特殊范围内。你的条件在这个范围之外,所以它不能访问那里的变量。在循环外声明它,它就能工作了:

int composite = 0;
do
{
    index += index;
    composite += index + 1;
    // more code here
} while (UnsetBitmask(bitmasks, composite));

根据规范,do .. while的条件变量应该在循环外声明,否则在每次迭代中该变量都会被重新初始化,这是没有意义的。

        int composite;
        do
        {
            index += index;
            composite = index + 1;
            // more code here
        } while (UnsetBitmask(bitmasks, composite)); 

更多一般规则:你不能使用其作用域之外的变量在c#中是{...},例如

  {
   int x = 123;
   ...
  }
  x = 456; // <- compile time error
代码中的

do {} while仅仅意味着作用域属于循环。

我明白,虽然"是否在块之外,但是考虑一下:

for (int i = 0; i < 10; i++) 
{
  Console.WriteLine(i);
}

这里,变量"i"是块作用域(在for's块之外不可见),实际上是一个新的instance"在每次循环迭代时创建。但是实际的定义在代码块之外。

你可以说"for"声明属于代码块,但之后我会写上&;while&;也属于块。这就是不一致!

    int composite;
do
{
   index += index;
   composite = index + 1;
   // more code here
} while (UnsetBitmask(bitmasks, composite));

如果您真的不想将变量声明移到循环体之外(正如所有答案所建议的那样),还有另一种(非常明显但非常丑陋的)解决方法:

do
{
   index += index;
   int composite = index + 1;
   // more code here
   // check the condition inside the loop body, where the variable exisits
   if(!UnsetBitmask(bitmasks, composite)) break;
} while (true);