出于兴趣,我想阅读有关这样设计的语言。哈斯克尔是一个,对吧?
我说的是执行此操作的语言,但也有编译器支持来捕获问题,如果它可以为空,那么你必须有适当的案例,处理编译等等。
它也只是函数式编程中的一个概念吗?它是否也存在于某些OO语言中?
答案 0 :(得分:2)
回答你问题的第一部分,你是对的,Haskell没有一个特殊的'null'值可以是任何类型。
如果您需要此行为,则必须更改函数的返回类型。通常,您使用Maybe类型,例如:
safeDiv :: Float -> Float -> Maybe Float
safeDiv a b
| b == 0 = Nothing
| otherwise = Just (a / b)
这表示safeDiv需要两个Floats并返回一个Maybe Float
类型。在函数体中,如果b为零,我可以返回Nothing
,否则我返回Just (a / b)
。
关键是你的类型签名明确标记你的函数是否可以返回Nothing
,并且任何调用者都将被迫以某种方式处理这两种可能的情况。
head
返回列表的第一个元素,如果列表为空则抛出错误,而不是返回包含在Maybe中的值。
答案 1 :(得分:2)
任何ML派生语言(其中Haskell是其中之一)都是这样工作的,包括SML和F#(虽然null
可以从.NET互操作泄漏到F#中)。 Scala通常还会调整null
,但它位于JVM之上的事实使得它对它的严格程度低于其他语言。
答案 2 :(得分:1)
你会发现Nullable是一个定义问题。
大多数语言都可以看到具有可空指针但不可为空的值。此外,许多语言提供了一个特殊的null / nil-object,变量可以自动初始化;你认为这可以为空吗?
一方面,它是一个特殊值,与变量通常保存的所有值(例如数字)不同,并且从那个角度看,就像只处理数字指针一样(可以为空)。
另一方面,这个null / nil-object是一个真实的对象,有一个真正的类(在基于类的OO语言中),并且会理解你发送给它的很多消息,比如asString(),所以因为它是真实的对象它在最严格意义上不是“空”吗?
答案 3 :(得分:1)
支持面向对象范例和非可空类型的两种语言(可以说是)C ++和(绝对)Spec#。
Spec#是API契约的形式语言(受JML,AsmL和Eiffel影响),它使用非空类型,前置条件,后置条件和对象不变量的构造扩展C#。 < br /> - 来自Microsoft Research的Spec#主页
后者可能没有被广泛使用(如果它被使用的话)。通过使用!
(例如object!
或string![]!
)后缀类型,您可以获得不可为空的类型。
关于C ++,我确信聪明的人会发现很多争论为什么不应该在这里提到C ++;作为一种复杂,细腻的语言,我确信存在这样的理由。我提到C ++的论点是,除了指针(*
)(很可能是0
)之外,C ++还有引用(&
),必须初始化为某些东西明智的。引用的主要问题是AFAIK,它们不能用于所有事情。可能存在某些情况,例如使用内存管理或智能指针,你无法完全摆脱指针。
最后,你总是可以尝试构建自己的非可空包装类型,例如:在C#中。可能与许多其他人一样,Jon Skeet已经这样做了blogged about it。这是一个可行的解决方案,但是这样的NotNull<T>
类型可能会感觉有点笨重,因为它没有真正集成到语言中,就像Spec#。
答案 4 :(得分:1)
已经提到过C ++。如果我从头开始设计一个C ++库(比如Qt),我实际上会在API中的各个点使用指针与引用来指示给定参数或返回类型是否为null。然后看到“*”和“ - &gt;”并不会主要是一个视觉指示器,你正在处理一个'非本地'对象 - 它会提醒你,你正在处理可能为空的东西,因此你最好检查它是否是。
Haskell的Maybe类型非常简单,但它是该语言最好的部分之一。在C ++中以这种方式做事并不能让你获得所有东西,但是它可以为你提供一些东西,我认为它会非常有用。 (简要回顾一下:如果一个函数参数不允许为null,检查它是否在运行时是一个遥远的第二个最佳选择:如果有人违反规则并给你一个null,即使你检查它仍然没有什么除了使用断言使程序崩溃之外,你可以做出更多合理的反应。编译器强制执行它不能为空,并且不允许调用者首先传入一个,这样做要好得多。)
(显然,如果你有一个空指针,你仍然可以盲目地取消引用它,传入它,然后反正崩溃。但至少你被迫取消引用(而不是传入)指针保持不变)是一个强大的提示,你应该检查是否为零。所以它总比没有好。)
答案 5 :(得分:0)
Haskell确实没有针对每种类型的特殊空值,但是如果你使用FFI允许你做的实际指针,你可以创建空指针。