就变量命名约定而言,应该命名迭代器i
还是更语义化的东西count
?如果你不使用i
,为什么不呢?如果您认为这i
是可以接受的,是否存在不应该使用它的迭代案例?
21 回答
取决于我想的上下文。如果您在某个集合中循环遍历一组对象,那么从上下文中您正在做什么应该是相当明显的。
for(int i = 0; i < 10; i++)
{
// i is well known here to be the index
objectCollection[i].SomeProperty = someValue;
}
但是,如果从上下文中不能立即清楚您在做什么,或者如果您正在修改索引,则应该使用更能说明用法的变量名称。
for(int currentRow = 0; currentRow < numRows; currentRow++)
{
for(int currentCol = 0; currentCol < numCols; currentCol++)
{
someTable[currentRow][currentCol] = someValue;
}
}
“i”对程序员来说意味着“循环计数器”。它没有任何问题。
这是另一个完全没问题的例子:
foreach (Product p in ProductList)
{
// Do something with p
}
我倾向于将 i、j、k 用于非常本地化的循环(就源代码行数而言仅存在很短的一段时间)。对于存在于较大源区域中的变量,我倾向于使用更详细的名称,这样我就可以看到它们的用途,而无需在代码中进行搜索。
顺便说一句,我认为这些命名约定来自早期的 Fortran 语言,我是第一个整数变量(A - H 是浮点数)?
i
是可以接受的,可以肯定的。然而,一个学期我从一位 C++ 老师那里学到了很多东西,他拒绝了对每个变量都没有描述性名称的代码。描述性地命名一切的简单行为迫使我更加努力地思考我的代码,并且在那门课程之后我编写了更好的程序,不是来自学习 C++,而是来自学习命名一切。Code Complete在这个主题上有一些好话。
我很好,但这样的事情不是:
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
string s = datarow[i][j].ToString(); // or worse
}
}
程序员在不经意间交换代码中的 i 和 j 是很常见的,尤其是当他们视力不好或他们的 Windows 主题是“热狗”时。对我来说,这总是一种“代码味道”——如果没有搞砸,这种情况很少见。
i 是如此常见以至于它是可以接受的,即使对于喜欢描述性变量名称的人也是如此。
绝对不可接受的(在我的书中是一个罪过)是在任何其他上下文中使用 i、j 或 k,而不是作为循环中的整数索引......例如
foreach(Input i in inputs)
{
Process(i);
}
我绝对可以接受。不知道我需要做出什么样的理由——但我确实一直在使用它,其他非常受人尊敬的程序员也这样做。
社会验证,我猜:)
是的,事实上它是首选,因为任何阅读您的代码的程序员都会明白它只是一个迭代器。
使用 i 而不是更具体的变量名有什么价值?为了节省 1 秒或 10 秒,或者甚至可能,甚至 30 秒的思考和打字?
使用 i 的成本是多少?也许什么都没有。也许代码很简单,使用 i 就可以了。但也许,也许,使用 i 将迫使未来使用此代码的开发人员不得不思考片刻“我在这里的意思是什么?” 他们将不得不思考:“它是一个索引、一个计数、一个偏移量还是一个标志?” 他们将不得不思考:“这种变化是否安全,是否正确,我会落后 1 分吗?”
在编写代码时使用 i 可以节省时间和精力,但最终可能会在未来花费更多的精力,甚至可能由于误解代码而导致无意中引入缺陷。
一般来说,大多数软件开发都是维护和扩展,因此阅读代码所花费的时间将大大超过编写代码所花费的时间。
很容易养成在任何地方使用有意义的名字的习惯,一旦你养成了这个习惯,用有意义的名字编写代码只需要几秒钟,但是你的代码更容易阅读、更容易理解等等显然是正确的。
我将 i 用于短循环。
没问题的原因是,我发现有人可以看到带有初始化程序的迭代器类型声明,然后在三行之后声称不清楚该变量代表什么,这完全令人难以置信。他们只是在假装,因为他们已经决定“有意义的变量名”必须意味着“长变量名”。
我实际这样做的原因是,我发现使用与手头的特定任务无关的东西,而且我只会在很小的范围内使用,这样我就不用担心我可能会使用一个具有误导性或模棱两可的名称,或者有一天会在更大范围内对其他东西有用。它是“i”而不是“q”或“count”的原因只是从数学中借来的惯例。
如果出现以下情况,我不使用 i:
- 循环体不小,或者
- 除了从范围开始到循环结束的前进(或后退)之外,迭代器执行任何操作:
i 不一定必须以 1 为增量,只要增量一致且清晰,当然可能会在 iterand 结束之前停止,但如果它改变方向,或者没有被循环的迭代修改(包括在前向循环中对 iterator.insertAfter() 的恶意使用),我尽量记住使用不同的东西。这表明“这不仅仅是一个平凡的循环变量,因此这可能不是一个平凡的循环”。
如果“更语义化的东西”是“迭代器”,那么没有理由不使用 i;这是一个很好理解的成语。
我认为我在 for 循环情况下是完全可以接受的。我一直觉得这是非常标准的,当我在这种情况下使用时,从来没有真正遇到过解释问题。foreach-loops 变得有点棘手,我认为这真的取决于你的情况。我很少在 foreach 中使用 i,仅在 for 循环中使用,因为我发现 i 在这些情况下太不具描述性了。对于 foreach 我尝试使用正在循环的对象类型的缩写。例如:
foreach(DataRow dr in datatable.Rows)
{
//do stuff to/with datarow dr here
}
无论如何,只是我的 0.02 美元。
如果您将其命名为描述它正在循环的内容,它会有所帮助。但我通常只使用 i.
只要您使用 i 来计算循环,或者使用从 0(或 1,取决于 PL)到 n 的索引的一部分,那么我会说 i 很好。
否则它可能很容易命名 i 一些有意义的东西,它不仅仅是一个索引。
我应该指出 i 和 j 也是矩阵索引的数学符号。通常,您正在遍历一个数组。所以这是有道理的。
只要您在一个简单的循环中临时使用它,并且很明显您在做什么,当然可以。也就是说,没有其他短词可以代替吗?
i
被广泛称为循环迭代器,所以如果你在循环之外使用它,你实际上更有可能混淆维护程序员,但如果你使用更具描述性的东西(如filecounter
),它会使代码更好。
这取决于。如果您正在迭代某些特定的数据集,那么我认为使用描述性名称更有意义。(例如,filecounter
正如丹建议的那样)。
但是,如果您正在执行任意循环,则i
可以接受。正如一位工作伙伴向我描述的那样 -i
是一种约定,意思是“这个变量只被for
循环构造修改。如果这不是真的,不要使用i
”
将 i、j、k 用于 INTEGER 循环计数器可以追溯到 FORTRAN 的早期。
只要它们是整数计数,就我个人而言,我对它们没有任何问题。
但后来我在 FORTRAN 上长大!
我的感觉是使用单个字母的概念对于“简单”循环来说很好,但是,我很久以前就学会了使用双字母并且效果很好。
// recommended style ● // "typical" single-letter style
●
for (ii=0; ii<10; ++ii) { ● for (i=0; i<10; ++i) {
for (jj=0; jj<10; ++jj) { ● for (j=0; j<10; ++j) {
mm[ii][jj] = ii * jj; ● m[i][j] = i * j;
} ● }
} ● }
如果好处不是很明显:在代码中搜索任何一个字母都会发现很多不是你想要的东西。该字母i
经常出现在不是您要查找的变量的代码中。
我已经这样做了至少10年了。
请注意,很多人评论说上述任何一个/两个都是“丑陋的”......
我要反对谷物,说不。
对于说“我被理解为迭代器”的人群,这可能是真的,但对我来说,这相当于“将值 5 分配给变量 Y”之类的评论。像评论这样的变量名称应该解释为什么/什么不是如何。
要使用先前答案中的示例:
for(int i = 0; i < 10; i++)
{
// i is well known here to be the index
objectCollection[i].SomeProperty = someValue;
}
像这样使用一个有意义的名字就更难了吗?
for(int objectCollectionIndex = 0; objectCollectionIndex < 10; objectCollectionIndex ++)
{
objectCollection[objectCollectionIndex].SomeProperty = someValue;
}
授予(借用的)变量名称 objectCollection 的名称也很糟糕。