空字符串应该隐式转换为false吗?

3

为什么

if (x) {
    f();
}

如果 x 是空字符串 "",是否调用 f()

在D语言中,空字符串是否会隐式转换为布尔值 false,就像Python和空数组一样(在D语言中)?

更新:我修正了问题。我错误地颠倒了推理逻辑。幸运的是,聪明的D语言大脑们仍然理解我的意思 ;)


为什么没有人给问题点赞,我不明白。 - Quonux
1
@Quonux:第一个猜测:因为D不是一种脚本语言... - DejanLekic
3个回答

10

条件语句、if语句和循环语句在编译器中被转换为bool类型。因此,

if(x) {...}

变成

if(cast(bool)x) {...}

对于数组而言,将其转换为bool类型等同于测试其ptr属性是否不为null。因此,它变成了:

if(x.ptr !is null) {...}

在数组的情况下,这实际上是一个非常糟糕的测试,因为null数组被认为与空数组相同。因此,在大多数情况下,您并不关心数组是否为null。数组本质上是一个类似结构体的东西。
struct Array(T)
{
    T* ptr;
    size_t length;
}
==运算符将检查ptr引用的所有元素是否相等,但如果两个数组的长度都是0,它就不关心ptr的值是什么。这意味着""null是相等的([]null也是相等的)。然而,is运算符显式地检查ptr属性是否相等,因此根据is运算符,""null不会相同,特定的空数组是否具有null ptr取决于它的值的设置方式。因此,数组为空并不能说明它是否为null。您必须使用is运算符进行确定。
由此产生的结果是,直接将数组(或字符串)放入条件语句中通常是不好的做法,就像您正在使用的那样。
if(x) {...}

相反,你应该明确你正在检查什么。你是否关心它是否为空?在这种情况下,您应该检查以下内容:
if(x.empty) {...}

或者

if(x.length == 0} {...}

或者你真的关心它是null吗?在这种情况下,请使用is运算符:

if(x is null) {...}

数组在条件语句中的行为与语言的其他部分一致(例如,指针和引用类型会检查它们是否为null),但不幸的是,在实践中,这种数组行为很容易出现错误。因此,我建议您永远不要将数组单独放在if语句或循环的条件中。


4
默认情况下,数组的转换查看.ptr,这意味着只有默认初始化的数组(或明确设置为null)才会评估为false。
作为附加效果,D中的字符串字面量是以\0结尾的,这意味着("")[0] == '\0',因此("").ptr不能为null(否则会导致段错误)。
在我看来,它应该查看长度,需要时可以使用ptr。

3

当我尝试时,它可以正常工作...

void main() {
    import std.stdio;
    string s = "";
    if(s)
            writeln("true"); // triggered
}

如果字符串的默认初始化为 "string s = null;",那么它不会通过测试,因为 null 转换为 false,但是在我的电脑上 "" 是可以通过测试的。你确定它不是 null 吗?
另外,如果你想测试是否为空,我更喜欢使用 if(x.length) 和 if(x.length == 0)。这两种方法都适用于 "" 和 null,如果你特别需要 null,则使用 if(x is null)。这样更加清晰明了,尤其是在 D 语言中,"" 和 null 在很多其他情况下是可以互换的。

我曾认为空的非空字符串也会隐式转换为 false。我一直认为不包含任何信息的类型实例应该隐式转换为 false。只是出于好奇...在什么情况下您希望出现这种行为? - Nordlöw
1
这是因为指针的缘故 - Jonathan的回答更详细。你为什么想要它?嗯,我不知道,我从来不用if(x)。有时我确实想知道它是否为空 - 想象一种情况,其中null表示用户没有输入任何信息,而“”表示他们完成了表单,但是故意将其留空。有时这很有用。但是if(x)有点奇怪,所以我更喜欢使用if(x is null)来精确检查。 - Adam D. Ruppe
好的。我同意,null被映射到“未定义”,而""被映射到零/空。 - Nordlöw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接