当程序员经常抱怨null错误/异常时,有人会问没有null我们该怎么办。
我对选项类型的酷有一些基本的概念,但我没有最好地表达它的知识或语言技能。对于下面的内容,什么样的解释对普通程序员来说是可以理解的呢?
默认情况下,不希望引用/指针为空 选项类型如何工作,包括简化检查空情况的策略,如 模式匹配和 单细胞生物的理解 替代解决方案,如消息吃nil (我错过的其他方面)
当程序员经常抱怨null错误/异常时,有人会问没有null我们该怎么办。
我对选项类型的酷有一些基本的概念,但我没有最好地表达它的知识或语言技能。对于下面的内容,什么样的解释对普通程序员来说是可以理解的呢?
默认情况下,不希望引用/指针为空 选项类型如何工作,包括简化检查空情况的策略,如 模式匹配和 单细胞生物的理解 替代解决方案,如消息吃nil (我错过的其他方面)
当前回答
Robert Nystrom在这里提供了一篇不错的文章:
http://journal.stuffwithstuff.com/2010/08/23/void-null-maybe-and-nothing/
描述了他在为Magpie编程语言添加缺席和失败支持时的思维过程。
其他回答
我总是把Null(或nil)看作是一个值的缺失。
有时你想这样,有时又不想。这取决于您正在处理的域。如果缺少中间名是有意义的:没有中间名,那么您的应用程序可以相应地执行。另一方面,如果不应该有空值:第一个名字是空的,那么开发人员会在凌晨2点接到电话。
我还见过代码因检查null而超载和过于复杂。对我来说,这意味着两件事之一: A)在应用程序树中更高的错误 B)糟糕的/不完整的设计
从积极的方面来看——Null可能是检查是否缺少某些东西的更有用的概念之一,没有Null概念的语言在进行数据验证时最终会使事情过于复杂。在这种情况下,如果新变量没有初始化,所述语言通常会将变量设置为空字符串0或空集合。但是,如果空字符串或0或空集合是应用程序的有效值——那么就有问题了。
有时,通过为字段创建特殊/奇怪的值来表示未初始化的状态,可以避免这种情况。但是当一个好心的用户输入特殊值时会发生什么呢?让我们不要陷入数据验证例程的混乱。 如果语言支持空概念,那么所有的关注点都将消失。
微软研究院有个有趣的项目叫做
spec#
它是一个c#扩展,具有非空类型和一些机制来检查你的对象是否为空,尽管,恕我直言,应用契约设计原则可能更合适,对许多由空引用引起的麻烦情况更有帮助。
Robert Nystrom在这里提供了一篇不错的文章:
http://journal.stuffwithstuff.com/2010/08/23/void-null-maybe-and-nothing/
描述了他在为Magpie编程语言添加缺席和失败支持时的思维过程。
矢量语言有时可以不使用null。
在本例中,空向量充当类型化null。
因为人们似乎忽略了它:null是模棱两可的。
Alice的出生日期为空。这是什么意思?
Bob的死亡日期为空。这是什么意思?
一个“合理”的解释可能是Alice的出生日期存在但未知,而Bob的死亡日期不存在(Bob仍然活着)。但是为什么我们会得到不同的答案呢?
另一个问题是:null是一个边缘情况。
null = null? nan = nan吗? 是否inf = inf? +0 = -0吗? +0/0 = -0/0?
答案通常分别是“是”、“否”、“是”、“是”、“否”、“是”。疯狂的“数学家”称NaN为“零”,并说它比较等于自身。SQL将null视为不等于任何东西(因此它们的行为类似于nan)。有人想知道,当您尝试将±∞、±0和nan存储到同一个数据库列中时会发生什么(有253个nan,其中一半是“负的”)。
更糟糕的是,数据库在对待NULL的方式上存在差异,而且大多数数据库并不一致(请参阅SQLite中的NULL处理了解概述)。这太可怕了。
现在是必须讲的故事:
我最近设计了一个(sqlite3)数据库表,有五列a NOT NULL, b, id_a, id_b NOT NULL, timestamp。因为它是一个通用模式,旨在解决相当任意应用程序的通用问题,所以有两个唯一性约束:
UNIQUE(a, b, id_a)
UNIQUE(a, b, id_b)
id_a只存在于与现有应用程序设计的兼容性(部分原因是我还没有提出更好的解决方案),并没有在新的应用程序中使用。由于NULL在SQL中的工作方式,我可以插入(1,2,NULL, 3, t)和(1,2,NULL, 4, t)而不违反第一个唯一性约束(因为(1,2,NULL) != (1,2, NULL))。
这是因为NULL在大多数数据库的唯一性约束下是如何工作的(可能是为了更容易模拟“现实世界”的情况,例如没有两个人可以有相同的社会安全号码,但并不是所有人都有一个)。
FWIW,如果不首先调用未定义的行为,c++引用不能“指向”null,并且不可能构造带有未初始化引用成员变量的类(如果抛出异常,构造失败)。
旁注:偶尔你可能想要互斥指针(即只有一个可以是非null),例如在一个假设的iOS类型DialogState = notshow | ShowingActionSheet UIActionSheet | ShowingAlertView UIAlertView |被驳回。相反,我被迫做一些事情,如assert((bool)actionSheet + (bool)alertView == 1)。