为什么我们没有两个空值?

时间:2009-02-25 09:00:09

标签: programming-languages null

我经常想知道为什么null代表“没有价值”的语言不能区分被动“我不知道它的价值是什么” 和更加自信的“没有价值。”

有几种情况我喜欢区分这两者(特别是在使用用户输入和数据库时)。

我想象以下内容,我们将两个州命名为unknownnull

var apple;

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

if (apple is null)
{
    sulk();
}
else
{
    eatApple(apple);
}

显然,我们可以通过手动将状态存储在其他地方but we can do that for nulls too来摆脱它。

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

27 个答案:

答案 0 :(得分:39)

我们一个是否足够糟糕?

答案 1 :(得分:34)

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

查看Null Object pattern。它可以帮助你实现你想要实现的目标。

答案 2 :(得分:34)

在我的编程中,我最近采用了区分“language null”和“domain null”的做法。

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

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

程序员使用null作为catch-all域null是很常见的,但我发现它往往会使代码更具程序性(更少面向对象)并且意图更难辨别。

每次想要一个null,问问自己:语言是null还是域null?

答案 3 :(得分:11)

javascript实际上既有null也有未定义(http://www.w3schools.com/jsref/jsref_undefined.asp),但很多其他语言都没有。

答案 4 :(得分:11)

在极少数情况下,当你需要这样的东西时,创建一个表示未知的静态常量会很容易。

var apple = Apple.Unknown;
while (apple == Apple.Unknown) {} // etc

答案 5 :(得分:7)

存在价值:

  • Python:vars().has_key('variableName')
  • PHP:isset(variable)
  • JavaScript:typeof(variable) != 'undefined'
  • Perl:(variable != undef)或如果您愿意:(defined variable)

当然,当变量未定义时,它不是NULL

答案 6 :(得分:3)

注意null是可接受但已知的条件。一个未知的状态是IMO的另一回事。我在最高职位的评论部分与Dan的谈话将澄清我的立场。谢谢Dan!。

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

Actionscript有这样的东西(nullundefined)。但是有一些限制。

请参阅documentation

  

无效数据类型

     

void数据类型只包含一个未定义的值。在以前版本的ActionScript中,undefined是Object类实例的默认值。在ActionScript 3.0中,Object实例的默认值为null。如果尝试将值undefined分配给Object类的实例,则Flash Player或Adobe AIR会将该值转换为null。您只能将未定义的值分配给无类型的变量。无类型变量是缺少任何类型注释的变量,或者对类型注释使用星号(*)符号。您只能将void用作返回类型注释。

答案 7 :(得分:3)

为什么要停在两点?

当我在大学学习数据库时,我们被告知有人(对不起,不记得研究员或论文的名字)看了一堆数据库模式,发现null有17种不同的含义:不知道“,”不能被称为“,”不适用“,”无“,”空“,”动作未采取“,”字段未使用“,等等。

答案 8 :(得分:2)

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

基本上,您的额外空值是排序的元信息,可以取决于类型的元信息。

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

在动态类型语言中,您必须考虑没有值的引用(null)与类型可能是任何内容的变量(未知或未定义)之间的差异

因此,例如,在静态类型的C#中,类型String的变量可以为null,因为它是引用类型。类型为Int32的变量不能,因为它是值类型,不能为null。我们总是知道这种类型。

在动态类型化的Javascript中,变量的类型可以保持未定义,在这种情况下,需要区分空引用和未定义的值。

答案 9 :(得分:2)

已经尝试过:Visual Basic 6没有Nothing,Null和Empty。它导致了如此糟糕的代码,在Dobbs博士的传奇Thirteen Ways to Loathe VB文章中排名第12位。

使用Null Object pattern代替,正如其他人所建议的那样。

答案 10 :(得分:2)

在haskell中你可以定义这样的东西:

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 ":-)"

这个想法是,未知值包含一些b类型的数据,可以将它们转换为已知值(如何执行此操作取决于具体类型ab

细心的读者会注意到我只是将Maybe和Either组合成一种数据类型:)

答案 11 :(得分:2)

在.net语言中,您可以使用nullable types来解决值类型的问题。

然而,问题仍然存在于参考类型。由于.net中没有指针这样的东西(至少在'safe'块中),“object?o”将无法编译。

答案 12 :(得分:2)

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

答案 13 :(得分:2)

Null类型是所有引用类型的子类型 - 您可以使用null而不是对任何类型的对象的引用 - 这会严重削弱类型系统。它被认为是historically bad idea by its creator中的一个,并且仅在检查地址是否为零时才存在,这很容易实现。

答案 14 :(得分:2)

在PHP Strict中,您需要对设置变量进行isset()检查(否则会发出警告)

if(!isset($apple))
{
    askForApple();
}

if(isset($apple) && empty($apple))
{
    sulk();
}
else
{
    eatApple();
}

答案 15 :(得分:2)

Some people will argue that we should be rid of null altogether,这似乎相当有效。毕竟,为什么要停在两个零位?为什么不是三个或四个,依此类推,每个代表“无价值”状态?

想象一下,refusednullinvalid

var apple;

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

if (apple is null)
{
    sulk();
}
else if(apple is invalid)
{
    discard();
}
else
{
    eatApple(apple);
}

答案 16 :(得分:1)

Some people已经领先一步了。 ;)

答案 17 :(得分:1)

boolean getAnswer() throws Mu

答案 18 :(得分:1)

考虑到西方哲学花了多长时间才弄清楚如何谈论“无所谓”的概念......是的,我对这种区别被忽视了一段时间并不感到惊讶。

答案 19 :(得分:0)

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

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

在“做其他事情”部分,从“好吧,忘记它”到尝试在其他地方获得“事物”,有各种各样的可能性。如果你不是简单地忽略NULL的东西,你可能需要知道为什么“thing”是NULL。有多种类型的NULL,可以帮助你回答这个问题,但是可能的答案很多,正如其他答案中暗示的那样。丢失的东西可能只是一个错误,在尝试获取它时可能是错误,它可能现在不可用,等等。要确定哪些案例适用于您的代码 - 这意味着您必须处理它们 - 它是特定于域的。因此,最好使用应用程序定义的机制来编码这些原因,而不是找到试图处理所有这些原因的语言功能。

答案 20 :(得分:0)

这是因为Null是您正在使用的语言的工件,而不是程序员的便利。它描述了对象在其使用环境中的自然发生状态。

答案 21 :(得分:0)

如果您使用的是.NET 3.0+并需要其他内容,则可以尝试使用Maybe Monad。您可以创建所需的“Maybe”类型,并使用LINQ语法相应地进行处理。

答案 22 :(得分:0)

AppleInformation appleInfo;    
while (appleInfo is null)
{
    askForAppleInfo();
}

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

首先,检查您是否有苹果信息,然后检查是否有苹果。您不需要不同的本地语言支持,只需使用正确的类。

答案 23 :(得分:0)

对我而言null表示缺乏价值,我尝试仅用它来表示。当然,您可以根据需要赋予null尽可能多的含义,就像您可以使用0或-1来表示错误而不是它们的数值。给一个表示赋予各种含义可能是模棱两可的,所以我不推荐它。

您的示例可以编码为apple.isRefused()或!apple.isValid(),但工作量很少;你应该事先定义什么是无效的苹果,所以我看不到有更多关键词的好处。

答案 24 :(得分:0)

您始终可以创建一个对象并将其分配给相同的静态字段以获得第二个空值。

例如,这用于允许元素为null的集合中。在内部,他们使用private static final Object UNSET = new Object作为未设置值,因此允许您在集合中存储null。 (我记得,Java的集合框架将此对象称为TOMBSTONE而不是UNSET。或者这是Smalltalk的集合框架吗?)

答案 25 :(得分:0)

VB6

  • 没什么 => “没有价值。”
  • => “我不知道它的价值是什么” - 与.NET中的DBNull.Value相同

答案 26 :(得分:0)

两个空值将是最糟糕的答案。如果一个null不够,则需要无穷大空值。

Null可能意味着:

  • '未初始化的'
  • '用户未指定'
  • '这里不适用,汽车颜色已被涂上颜色'
  • 'Unity:这个域有零位信息。'
  • '空:在这种情况下,这正确地保留了数据,例如上次轮胎在新车上旋转'
  • '多个,级联空值:例如,未指定数量时的数量价格的延伸乘以用户未指定的数量'

您的特定域名可能需要许多其他类型的“带外”值。实际上,这些值都在域中,并且在每种情况下需要具有明确定义的含义。 (ergo,无穷大真的是零)