null
用法取决于应用程序/语言
最终,是否null
用作有效的应用程序值的选择很大程度上取决于您的应用程序和编程语言/接口/边缘。
从根本上讲,如果值的类别不同,我建议尝试使用不同的类型。null
如果您的界面允许,并且您要表示的属性只有两个类,则可以选择。如果界面或格式允许,则可以忽略属性。新的聚合类型(类,对象,消息类型)可能是另一种选择。
对于您的字符串示例,如果这是用编程语言编写的,我会问自己几个问题。
- 我打算增加将来的价值类型吗?如果是这样,那么
Option
对于您的界面设计来说可能会更好。
- 我什么时候需要验证消费者电话?静态地?动态地?之前?后?都没有 如果您的编程语言支持,请使用静态类型的好处,因为它避免了为验证而必须创建的代码量。
Option
如果您的字符串不可为空,则可能最适合此情况。但是,null
无论如何,您仍然可能必须检查用户输入的字符串值,因此我可能会推迟到第一行提问:我想/将要表示多少种类型的值。
- 是否
null
显示我的编程语言中的程序员错误?不幸的是,null
在某些语言中,通常是未初始化(或未明确初始化)的指针或引用的默认值。是null
因为作为默认值可接受的值?它是安全的默认值?有时null
表示已释放的值。我是否应该为接口的使用者提供程序中潜在的内存管理或初始化问题的指示?面对此类问题,此类呼叫的失败模式是什么?调用者是否与我的线程处于同一进程或线程中,从而使此类错误对我的应用程序构成高风险?
根据您对这些问题的回答,您可能可以磨练是否null
适合您的界面。
例子1
- 您的应用程序对安全至关重要
- 您在启动时使用某种类型的堆初始化,并且
null
是在无法为字符串分配空间时可能返回的可能的字符串值。
- 这样的字符串可能会击中您的界面
答:null
可能不合适
基本原理:null
在这种情况下,实际上是用来指示两种不同类型的值。第一个可能是您的界面用户可能想要设置的默认值。不幸的是,第二个值是一个标志,指示您的系统运行不正常。在这种情况下,您可能希望尽可能安全地失败(无论对您的系统意味着什么)。
例子2
- 您正在使用具有
char *
成员的C结构。
- 您的系统不使用堆分配,而是在使用MISRA检查。
- 您的接口接受此结构作为指针,并检查以确保该结构未指向
NULL
char *
API成员的默认值和安全值可以由单个值表示NULL
- 在用户的结构初始化后,您希望为用户提供不显式初始化
char *
成员的可能性。
答:NULL
可能合适
基本原理:您的结构通过NULL
检查但未初始化的可能性很小。但是,除非您对结构值进行某种校验和和/或对结构地址进行范围检查,否则您的API可能无法解决这一问题。MISRA-C linter可以通过在初始化之前标记结构的使用来帮助您的API用户。但是,对于char *
成员,如果指向struct的指针指向已初始化的struct,NULL
则为struct初始化程序中未指定成员的默认值。因此,它NULL
可以作为char *
应用程序中struct成员的安全默认值。
如果它在序列化接口上,我会问自己以下问题,有关是否在字符串上使用null。
- 是否
null
表明潜在的客户端错误?对于JavaScript中的JSON,这可能是一个“否”,null
并不一定表示分配失败。在JavaScript中,它被用作指示要设置成问题的引用中对象缺失的明确指示。但是,有一些非JavaScript解析器和序列化器可将JSON映射null
到本机null
类型。如果是这种情况,那么就开始讨论null
您的特定语言,解析器和序列化器组合是否可以使用本机用法。
- 明确缺少属性值是否会比单个属性值影响更多?有时,a
null
实际表示您完全具有新的消息类型。仅指定完全不同的消息类型,对于使用序列化格式的用户来说可能更干净。这确保了它们的验证和应用程序逻辑可以将Web界面提供的消息的两种区别完全分开。
一般建议
null
不能是不支持边缘或接口的值。如果您使用的属性值类型(例如JSON)的输入极其松散,请尝试在使用者边缘软件(例如JSON Schema)上推送某种形式的模式或验证。如果它是一种编程语言API,则在可能的情况下(通过键入)静态验证用户输入,或者在运行时尽可能合理地验证用户输入(也可以在面向消费者的界面上进行防御性编程)。重要的是,记录或定义边,因此毫无疑问:
- 给定属性接受什么类型的值
- 哪些值范围对于给定属性有效。
- 聚合类型应如何构造。聚合类型必须/应该/可以存在哪些属性?
- 如果是某种类型的容器,那么该容器可以容纳或应该容纳多少个项目,以及该容器可以容纳哪些值?
- 容器或集合类型的属性或实例返回什么顺序(如果有)?
- 设置特定值有什么副作用?读取这些值有什么副作用?