是
while (k >= 0 && arr[k] > 0)
安全的?
当 k 在范围内并且 arr[k] > 0 时它会循环。但我不知道这是否是编码的好习惯。我知道如果我们这样做
while (arr[k] > 0 && k >= 0)
这将是一场灾难。
是
while (k >= 0 && arr[k] > 0)
安全的?
当 k 在范围内并且 arr[k] > 0 时它会循环。但我不知道这是否是编码的好习惯。我知道如果我们这样做
while (arr[k] > 0 && k >= 0)
这将是一场灾难。
&&
短路是安全的。如果k
小于零,则不会对其进行索引arr
。
这可能是不安全的,因为您的 while 循环体可能不会k
正确递减,从而导致无限循环。k
或者如果超出arr
's bounds可能不安全。
您还应该关心数组大小:
while (k >= 0 && k < arr.length && arr[k] > 0)
将是一个更安全的代码。
是的,这是一个很好的做法。事实上,这也是发明短路 &&
算子的部分原因。运算符从左到右计算其子表达式,并在找到错误的子表达式时停止。这正是您想要的;运算符&&
允许您在一行中表达这一点。
关于表达:
而 (k >= 0 && arr[k] > 0) { ... }
不,这不安全。
该表达式k >= 0 && arr[k] > 0
在某种程度上是安全的,它确保仅arr[k]
使用正索引 of (因为在这些情况下,不会评估第二个操作数&&
的快捷方式值)。k < 0
arr[k] > 0
但请注意,不能保证索引超出范围(例如 for k >= arr.length
) - 并且 arr 也可能是null
。因此,您可以获得一个IndexOutOfRangeException
或一个NullReferenceException
- 如果未处理,您的应用程序将中断。
为避免这种情况,请使用
if (k >=0 && arr != null)
{
while (k<arr.Length && arr[k] > 0) { ... k++; }
}
在上面的代码中,如果arr
是null
,则可以跳过循环,因为数组中没有元素。如果超出数组长度(即k>=arr.length
),则arr[k] > 0
不再检查(从而避免发生异常)。
我已将表达式的不变部分k >=0 && arr != null
从循环表达式中取出,因为没有必要(并且运行速度会更慢)在循环的每次迭代中对其进行评估。
与for
循环相同:
if (k >=0 && arr != null)
for (; var k=0; k<arr.Length && arr[k] > 0; k++) { ... }
请注意,因为您不是从 0 开始,所以我跳过了初始化var k=0
,我假设您已经在源代码的上方某处完成了初始化。
除此之外,还有一些附加信息- 如果您想了解有关逻辑运算符和副作用的一些有趣细节,请继续阅读。
在C/C++/C#&
中,重要的是要知道vs.&&
和|
vs. ||
:之间的区别,&
并|
“按位”评估整个表达式,而&&
如果||
结果已经清楚则停止评估(如果有任何部分,逻辑and
不能是true
表达式是;如果表达式的任何部分是 ),则false
逻辑or
不能是)。false
true
但是,在某些情况下,您也需要“非快捷方式”版本&
。假设您想要将字符串数组转换为整数数组,并且您想要转换每个可以转换的值,即使有些值不能转换为整数(其他值应保持 0) - 如下例所示:
void Main()
{
var sArr = new string[] {"4", "2", "x", "y", "10", "11"};
var iArr = new int[sArr.Length];
bool bCheck = true;
for (var i=0; i<sArr.Length; i++)
{
int value=0;
// need to use & instead of && here:
bCheck = bCheck && int.TryParse(sArr[i], out value);
iArr[i]=value;
};
if (bCheck==true)
{
Console.WriteLine("All numbers are okay.");
}
foreach (var n in iArr) Console.Write(n.ToString() + " ");
Console.WriteLine();
}
此代码的目的是将字符串数组中的值一一转换为 int 并将它们存储在整数数组中 - 如果元素不包含有效整数,则它存储值 0 代替。
我们在这里得到的输出是
4 2 0 0 0 0
这不是我们所期望的,因为 10 和 11 也是有效的整数并且应该被转换,相反我们得到了它们的 0 和 0。
为了得到我们期望的结果,即
4 2 0 0 10 11
我们需要替换&&
为&
:
bCheck = bCheck & int.TryParse(sArr[i], out value);
这里有什么区别?
如果您在&&
上面的语句中使用,那么只要 bCheck 计算结果为 false,快捷方式就会完成——这通常是正确的,因为这样我们就不必再检查表达式了,因为不可能被计算为 true .
但也会发生的情况是,由于我们有快捷方式,int.TryParse
不再被调用,因此值不会从函数中传递出去——循环中的所有后续调用都将评估为 0,而不管sArr[i]
.
这是我们在这里遇到的意外副作用,可以通过强制评估每个表达式来修复(通过使用&
)。