2

如果我有这个代码:

if (isFoo() && isBar())
{
    ...
}

程序会先计算第一个条件,再计算第二个条件,然后判断是通过还是跳过下面的块。

但是,如果我像这样嵌套条件:

if (isFoo())
    if(isBar())
    {
        ...
    }

现在它检查第一个条件,如果它是假的,它不会打扰第二个条件。

如果第二个条件(作为一个函数)是一个耗时的内存昂贵的猪,那么嵌套它似乎更好。

这是真的?我以前从未见过这样的代码,我在第一个示例之后做了一个假设,但 IMO 很有可能。

4

6 回答 6

3

这取决于编程语言。

大多数现代/流行语言都支持短路评估,这意味着程序不会评估整个表达式,而是在获得整个表达式的结果后立即停止评估(其他人已经给出了示例)。

但也有例外

我知道不支持短路评估的两种语言是 Microsoft VB(6) 和 VB.NET。

VB6根本不支持,所以这里嵌套Ifs if是常用的优化技术。此外,在诸如

If Not rs Is Nothing And Not rs.EOF

不使用嵌套Ifs 会导致执行错误,而rsis Nothing

VB.NET引入了两个新的逻辑运算符AndAlsoOrElse它们支持短路评估。

标准VB.NET AndOr运营商不支持短路评估,这是新手开发人员常见的错误来源。

优化

在这两种情况下(语言支持而不是短路评估),您都可以检查表达式,以便更快地评估 first

因此,而不是(如果用户是女性,使用偶数键并且它已登录,则检查 DB):

if (db.getUserSex() == FEMALE && userKey % 2 == 0 && userKey % 2 && isUserLogged)

使用(检查是否登录(布尔值),使用偶数键(算术运算符)并最后检查数据库中的性别):

if (isUserLogged && userKey % 2 == 0 && db.getUserSex() == FEMALE)
于 2012-12-30T09:11:27.427 回答
2

在 C#/C++ 和许多其他语言中,您AND实际上有两个逻辑运算符:&&&:

&操作员将评估这两个条件

&&运算符将仅首先计算,如果等于FALSE,则跳过表达式的第二部分。

这同样适用于逻辑OR运算符。有两个运算符:|||

|操作员将评估这两个条件

||运算符将仅首先计算,如果等于TRUE,则跳过表达式的第二部分。

因此,回答您的问题,在您使用的示例中&&,它将表现为两个嵌套if

[编辑]:好的,找到使用 | 的例子并不容易 和 &,我个人在最短代码竞赛中使用过它们))这是它们真正有用的地方(不是因为它们比 && 和 || 短)。还要考虑以下示例:

static bool LaunchFirstRocket()
{
    // Launching rocket if all is ok return true, or return false if we failed to launch it.
}

static bool LaunchSecondRocket()
{
    // Launching rocket if all is ok return true, or return false if we failed to launch it.
} 

static void Main(string[] args)
{
    if (LaunchFirstRocket() & LaunchSecondRocket())
    {
        Console.WriteLine("Both rockets have launched successfully!");
    }
}

在这里,无论第一个方法的结果如何,我们都将强制执行这两种方法。如果第一颗火箭失败了,我们还想发射第二颗,这是我们的逻辑。是的,还有很多其他方法可以编写此类代码,但这只是用于教育目的的示例。

于 2012-12-30T08:48:40.983 回答
1

我相信大多数编译器都会为你做这个优化。如果 && 的第一个条件为假,则不会执行第二个条件。

于 2012-12-30T08:39:10.707 回答
1

程序将计算第一个条件,然后计算第二个条件,

不,不是在大多数现代语言中(例如 C、C++)。由于已知如果第一个条件为假,则AND表达式的值不可能是假以外的任何值,因此不评估第二部分。在这两种语言中,标准明确定义了这种优化(称为“短路评估”)。

于 2012-12-30T08:40:46.987 回答
1

这取决于。正如其他人所指出的,在具有短路评估的编译语言(例如 C 和 C++)中,两个版本都可能编译为完全相同的代码。

在某些解释性语言中,例如 Perl,第二个版本实际上可能第一个版本慢很多,因为输入代码块的开销很小。例如,这个人工基准清楚地显示了差异:

use Benchmark ':all';
my $count = shift || 10_000_000;
our ($foo, $bar, $baz) = (1, 1, 1);
timethese( $count, {
    'and'    => 'if ($foo && $bar) { $baz++; }',
    'nested' => 'if ($foo) { if ($bar) { $baz++; } }',
});

输出:

Benchmark: timing 10000000 iterations of and, nested...
       and:  2 wallclock secs ( 2.41 usr +  0.00 sys =  2.41 CPU) @ 4149377.59/s (n=10000000)
    nested:  4 wallclock secs ( 3.54 usr +  0.00 sys =  3.54 CPU) @ 2824858.76/s (n=10000000)

当然,在实践中,这种差异可能完全是微不足道的,尤其是与开始使用解释语言的一般开销相比。

于 2012-12-30T08:58:48.997 回答
0

所有现代语言都会短路任何 AND'ed 子句。所以,在你的例子中,如果 isFoo() 为假,它甚至不会检查 isBar(),它会退出 if 语句。

于 2012-12-30T08:39:35.100 回答