Programming languages 为什么不';我们不是有两个空的吗?

Programming languages 为什么不';我们不是有两个空的吗?,programming-languages,null,Programming Languages,Null,我经常想知道为什么带有表示“无值”的null的语言不区分被动的“我不知道值是什么”和更自信的“没有值” 在一些情况下,我希望将两者区分开来(特别是在处理用户输入和数据库时) 我想象如下,我们将两个状态命名为未知和空: var apple; while (apple is unknown) { askForApple(); } if (apple is null) { sulk(); } else { eatApple(apple); } 显然,我们可以通过手动将状态

我经常想知道为什么带有表示“无值”的
null
的语言不区分被动的“我不知道值是什么”和更自信的“没有值”

在一些情况下,我希望将两者区分开来(特别是在处理用户输入和数据库时)

我想象如下,我们将两个状态命名为
未知

var apple;

while (apple is unknown)
{
    askForApple();
}

if (apple is null)
{
    sulk();
}
else
{
    eatApple(apple);
}
显然,我们可以通过手动将状态存储在其他地方而不使用它


因此,如果我们可以有一个
null
,为什么不能有两个呢?

在.net语言中,您可以使用,它解决了值类型的这个问题


但是,对于引用类型,问题仍然存在。由于.net中没有指针(至少在“安全”块中是这样),所以“object?o”不会编译。

在大多数编程语言中,null表示“空”或“未定义”。另一方面,“未知”则有所不同。本质上,“未知”描述对象的状态。此状态必须来自程序中的某个位置


看一看这张照片。它可能会帮助您实现您想要实现的目标。

javascript实际上既有null也有undefined(),但许多其他语言都没有。

注意
null
是一种可接受但已知的条件。在我看来,未知状态是另一回事。我在帖子的评论部分与丹的对话将阐明我的立场。谢谢你,丹

您可能想要查询的是对象是否已初始化

Actionscript有这样一个东西(
null
未定义
)。但是有一些限制

见:

无效数据类型

void数据类型仅包含一个未定义的值。在ActionScript的早期版本中,未定义是对象类实例的默认值。在ActionScript 3.0中,对象实例的默认值为null。如果试图将未定义的值分配给对象类的实例,Flash Player或Adobe AIR会将该值转换为null。只能将未定义的值指定给未类型化的变量。非类型化变量是缺少任何类型注释或使用星号(*)符号进行类型注释的变量。只能将void用作返回类型注释


有一个空值还不够糟糕吗?

在我的编程中,我最近采用了区分“语言空值”和“域空值”的做法

“语言null”是编程语言提供的特殊值,用于表示变量“无值”。它需要作为数据结构、参数列表和返回值中的伪值

“域空”是实现设计模式的任意数量的对象。实际上,每个域上下文都有一个不同的域null

对于程序员来说,使用语言null作为一个全包域null是相当常见的,但是我发现它会使代码更程序化(不太面向对象),并且更难辨别意图


每当想要一个空值时,问问自己:这是一个语言空值还是一个域空值?

创建一个表示未知的静态常量非常容易,在极少数情况下,您需要这样的东西

var apple = Apple.Unknown;
while (apple == Apple.Unknown) {} // etc
,这似乎相当合理。毕竟,为什么要停在两个零位呢?为什么不是三个或四个等等,每个代表一个“无价值”状态

想象一下,如果
被拒绝
为空
无效

var apple;

while (apple is refused)
{
    askForApple();
}

if (apple is null)
{
    sulk();
}
else if(apple is invalid)
{
    discard();
}
else
{
    eatApple(apple);
}
价值的存在:

  • Python:
    vars()。具有_键('variableName')
  • PHP:
    isset(变量)
  • JavaScript:
    typeof(变量)!='未定义的“
  • Perl:
    (变量!=unde)
    或者如果您愿意:
    (定义变量)

当然,当变量未定义时,在PHP Strict中它不是空的,您需要对设置的变量执行
isset()
检查(否则会抛出警告)


Null类型是所有引用类型的子类型-您可以使用Null而不是对任何类型的对象的引用-这严重削弱了类型系统。它被认为是a中的一个,只存在于检查地址是否为零容易实现的情况下

至于为什么我们没有两个空值,是不是因为历史上在C语言中,空值是一个简单的
#define
而不是语言的一个独特部分?

我认为有一个空值是处理基本模式的较低公分母

if thing is not NULL
  work with it
else
  do something else

在“做其他事情”部分,有很多种可能性,从“好吧,忘了它”到尝试在其他地方做“事情”。如果您不只是忽略空值的东西,您可能需要知道为什么“thing”是空的。如果有多种类型的NULL,将有助于您回答该问题,但可能的答案很多,正如这里的其他答案所暗示的。丢失的东西可能只是一个bug,可能是试图获取它时出错,可能现在不可用,等等。要决定哪些情况适用于您的代码——这意味着您必须处理它们——它是特定于域的。因此,最好使用应用程序定义的机制对这些原因进行编码,而不是找到一种语言功能来处理所有这些原因。

问题在于,在强类型语言中,这些额外的空值应该包含有关类型的特定信息

基本上,额外的null是某种类型的元信息,可以依赖于类型的元信息

某些值类型具有此额外信息,例如许多数值类型具有NaN常量

在动态类型语言中,必须考虑无值引用(null)和类型可能为任何类型(未知或未定义)的变量之间的差异

例如,在静态类型C#中,类型为if thing is not NULL work with it else do something else
data MaybeEither a b = Object a
                     | Unknown b
                     | Null
                       deriving Eq
main = let x = Object 5 in
       if x == (Unknown [2]) then putStrLn ":-("
       else putStrLn ":-)"
AppleInformation appleInfo;    
while (appleInfo is null)
{
    askForAppleInfo();
}

Apple apple = appleInfo.apple;
if (apple is null)
{
    sulk();
}
else
{
    eatApple(apple);
}
boolean getAnswer() throws Mu