【问题标题】:Why don't we have two nulls?为什么我们没有两个空值?
【发布时间】:2009-02-25 09:00:09
【问题描述】:

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

在某些情况下,我希望区分这两者(尤其是在使用用户输入和数据库时)。

我想象如下,我们将两个状态命名为 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,为什么我们不能有两个?

【问题讨论】:

  • 你真的是在谈论两个空值还是一个null 和一个不确定的状态?请澄清。
  • 你如何定义'null'?我说的是“没有价值”的价值观。
  • 我认为它可以与一个可以返回null但也可以抛出(“未知”)的函数进行比较。

标签: programming-languages null


【解决方案1】:

我们有 一个 null 还不够糟糕吗?

【讨论】:

  • 因为 null 不是类型的正确值。如果我有一个 Car 类型的变量,我希望能够调用 car.drive() 而不必担心它实际上可能根本不是汽车。其他状态应该在其他变量中。
  • @Dan 在 C++ 中,“Car”类型的变量(或对 Car 的引用,“Car&”)永远不会为空。当然,指向 Car ("Car*") 的 指针 可以为 null,即指针可以指向 Car 对象或不指向任何对象。
  • @Avi:问题不在于有两个空值,正如我所说,它是关于有一个空值和一个未知的值。恕我直言,它们是完全不同的两件事。
  • @dirkgently:没有。这只是编程的一个事实,如果你不初始化一个变量,那么它就不会被初始化。是的,它们可以由编译器自动初始化,但这不是重点。
  • 这有关系吗? qconlondon.com/london-2009/presentation/… “我称之为十亿美元的错误。它是 1965 年空引用的发明。”
【解决方案2】:

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

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

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

程序员将语言 null 用作包罗万象的域 null 是相当普遍的,但我发现它往往会使代码更加程序化(更少面向对象)并且更难辨别意图。

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

【讨论】:

  • 接受域区分。我宁愿根本不必考虑“语言空值”,但似乎它们已成为一种必要的邪恶。
【解决方案3】:

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

看看Null Object pattern。它可能会帮助您实现您想要实现的目标。

【讨论】:

    【解决方案4】:

    javascript 实际上有 null 和 undefined (http://www.w3schools.com/jsref/jsref_undefined.asp),但许多其他语言没有。

    【讨论】:

    • 确实如此。以前使用 Javascript 的经验是让我想知道的事情之一。
    • 如果你有一个动态类型的语言,你需要两者 - undefined = 类型未知且其中没有任何内容,null = 指向任何内容的引用类型。在像 C# 这样的静态类型语言中,您总是有一个类型,因此不需要 undefined。
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

      存在价值:

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

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

      【讨论】:

      • 或者在 perl 哈希中, if (exists $table{key} ) 看是否有一个键,更不用说看它是否有值。
      【解决方案7】:

      为什么要停在两点?

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

      【讨论】:

        【解决方案8】:

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

        这个想法是 Unknown 值包含一些 b 类型的数据,可以将它们转换为已知值(您将如何做到这一点取决于具体类型 ab)。

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

        【讨论】:

        • 哈!我发布了与您类似的内容。我对 Haskell 还不是很熟悉,但感谢您发布此内容。
        【解决方案9】:

        Null 类型是所有引用类型的子类型——您可以使用 null 代替对任何类型对象的引用——这严重削弱了类型系统。它被认为是historically bad idea by its creator 之一,并且仅在检查地址是否为零时易于实现。

        【讨论】:

          【解决方案10】:

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

          【讨论】:

            【解决方案11】:

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

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

            【讨论】:

              【解决方案12】:

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

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

              【讨论】:

              • 只有值类型可以为空,所以它不是引用类型的第二个空。它只为值类型引入了一个“未定义”状态,否则它总是有一个值。
              • "可空类型是 System..::.Nullable)>) 结构的实例。可空类型可以表示其基础值类型的正确值范围,加上一个额外的空值。”所以它就像一个 Haskell “Maybe”,但仅适用于原语?
              【解决方案13】:

              注意null 是可接受但已知的条件。未知状态是 IMO 的另一回事。我在顶部帖子的 cmets 部分与 Dan 的对话将阐明我的立场。谢谢丹!

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

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

              documentation:

              空数据类型

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

              【讨论】:

                【解决方案14】:

                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);
                }
                

                【讨论】:

                • 那就太好了。嗯... null 的子类?
                • 其中一个“某些人”是 NULL 的发明者,就在几周前,他在 QCon London 2009 的“Historically Bad Ideas”轨道上的演讲中称其为“十亿美元的错误” : QConLondon.Com/london-2009/presentation/…>
                • //缺少分号 :oP => discard();
                • 在超链接检测到达之前 > 被编码为 >。想清楚。这是一个坚实的原则,思考? :)
                【解决方案15】:

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

                按照其他人的建议,改用Null Object pattern

                【讨论】:

                  【解决方案16】:

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

                  基本上,您的额外空值是一种元信息,可能取决于类型。

                  一些值类型有这个额外的信息,例如许多数字类型有一个 NaN 常量。

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

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

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

                  【讨论】:

                    【解决方案17】:

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

                    【讨论】:

                    • 看看 .Net 中的可空类型 - 这比将任意值分配给 null 要好得多。
                    • 你知道我在开玩笑……对吧?这是一个每日 WTF 链接。我永远不会推荐这个或 OP 的要求。
                    • 我没有,抱歉。有时我认为我们程序员太讽刺了:-/
                    【解决方案18】:
                    boolean getAnswer() throws Mu
                    

                    【讨论】:

                      【解决方案19】:

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

                      【讨论】:

                        【解决方案20】:

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

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

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

                        【讨论】:

                          【解决方案21】:

                          这是因为 Null 是您正在使用的语言的产物,而不是程序员的便利。它描述了对象在使用它的上下文中自然发生的状态。

                          【讨论】:

                            【解决方案22】:

                            如果您使用的是 .NET 3.0+ 并且需要其他东西,您可以试试Maybe Monad。您可以创建所需的任何“可能”类型,并使用 LINQ 语法进行相应处理。

                            【讨论】:

                              【解决方案23】:
                              AppleInformation appleInfo;    
                              while (appleInfo is null)
                              {
                                  askForAppleInfo();
                              }
                              
                              Apple apple = appleInfo.apple;
                              if (apple is null)
                              {
                                  sulk();
                              }
                              else
                              {
                                  eatApple(apple);
                              }
                              

                              首先检查是否有苹果信息,然后检查是否有苹果。您不需要为此提供不同的母语支持,只需使用正确的类即可。

                              【讨论】:

                                【解决方案24】:

                                对我来说,null 代表缺乏价值,我试图用它来代表它。当然,你可以赋予 null 任意多的含义,就像你可以使用 0 或 -1 来表示错误而不是它们的数值一样。但是,给一种表示赋予不同的含义可能会模棱两可,所以我不推荐它。

                                您的示例可以编写为 apple.isRefused() 或 !apple.isValid() 之类的代码,而且工作量很小;无论如何,您应该事先定义什么是无效苹果,所以我看不到拥有更多关键字的好处。

                                【讨论】:

                                  【解决方案25】:

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

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

                                  【讨论】:

                                    【解决方案26】:

                                    VB6

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

                                    【讨论】:

                                      【解决方案27】:

                                      两个空值将是最错误的答案。如果一个 null 还不够,您需要无穷多个 null。

                                      Null 可能意味着:

                                      • '未初始化'
                                      • '用户未指定'
                                      • '此处不适用,汽车涂漆前的颜色'
                                      • 'Unity:此域的信息位为零。'
                                      • '空:在这种情况下正确地不保存任何数据,例如上次在新车上旋转轮胎的时间'
                                      • '多个,级联空值:例如,当没有指定数量时,数量价格的扩展乘以用户未指定的数量'

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

                                      【讨论】:

                                        猜你喜欢
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2019-05-03
                                        • 1970-01-01
                                        • 2022-11-28
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多