关于不可为空类型的争论 [英] About the non-nullable types debate

查看:36
本文介绍了关于不可为空类型的争论的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直听到人们谈论不可空引用类型如何解决如此多的错误并使编程变得如此简单.甚至 null 的创建者也称其为他的十亿美元的错误,以及Spec# 引入了不可为空的类型来解决这个问题.

I keep hearing people talk about how non-nullable reference types would solve so many bugs and make programming so much easier. Even the creator of null calls it his billion dollar mistake, and Spec# has introduced non-nullable types to combat this problem.

请忽略我对 Spec# 的评论.我误解了它的工作原理.

Ignore my comment about Spec#. I misunderstood how it works.

EDIT 2:我一定是在和错误的人说话,我真的希望有人与之争论:-)

EDIT 2: I must be talking to the wrong people, I was really hoping for somebody to argue with :-)

所以我猜,作为少数,我错了,但我不明白为什么这场辩论有任何价值.我认为 null 是一个错误查找工具.考虑以下几点:

So I would guess, being in the minority, that I'm wrong, but I can't understand why this debate has any merit. I see null as a bug-finding tool. Consider the following:

class Class { ... }

void main() {
    Class c = nullptr;
    // ... ... ... code ...
    for(int i = 0; i < c.count; ++i) { ... }
}

砰!访问冲突.有人忘记初始化c.

BAM! Access violation. Someone forgot to initialize c.

现在考虑一下:

class Class { ... }

void main() {
    Class c = new Class(); // set to new Class() by default
    // ... ... ... code ...
    for(int i = 0; i < c.count; ++i) { ... }
}

哎呀.循环被悄悄地跳过.追踪问题可能需要一段时间.

Whoops. The loop gets silently skipped. It could take a while to track down the problem.

如果你的类是空的,代码无论如何都会失败.为什么不让系统告诉您(尽管有点粗鲁),而不必自己弄清楚?

If your class is empty, the code is going to fail anyway. Why not have the system tell you (albeit slightly rudely) instead of having to figure it out yourself?

推荐答案

有点奇怪的是,该线程中标记为answer"的响应实际上首先突出了 null 的问题,即:

Its a little odd that the response marked "answer" in this thread actually highlights the problem with null in the first place, namely:

我还发现我的大部分 NULL指针错误围绕功能从忘记检查返回string.h的函数,其中 NULL 用作指示符.

I've also found that most of my NULL pointer errors revolve around functions from forgetting to check the return of the functions of string.h, where NULL is used as an indicator.

如果编译器能够在编译时而不是运行时捕获这些类型的错误,那不是很好吗?

Wouldn't it be nice if the compiler could catch these kinds of errors at compile time, instead of runtime?

如果您使用过类似 ML 的语言(在某种程度上,SML、OCaml、SML 和 F#)或 Haskell,则引用类型是不可为空的.相反,您通过将其包装为选项类型来表示空"值.通过这种方式,如果函数可以返回 null 作为合法值,则您实际上更改了函数的返回类型.所以,假设我想从数据库中拉出一个用户:

If you've used an ML-like language (SML, OCaml, SML, and F# to some extent) or Haskell, reference types are non-nullable. Instead, you represent a "null" value by wrapping it an option type. In this way, you actually change the return type of a function if it can return null as a legal value. So, let's say I wanted to pull a user out of the database:

let findUser username =
    let recordset = executeQuery("select * from users where username = @username")
    if recordset.getCount() > 0 then
        let user = initUser(recordset)
        Some(user)
    else
        None

Find user 的类型是 val findUser : string -> user option,所以函数的返回类型实际上告诉你它可以返回一个空值.要使用代码,您需要处理 Some 和 None 两种情况:

Find user has the type val findUser : string -> user option, so the return type of the function actually tells you that it can return a null value. To consume the code, you need to handle both the Some and None cases:

match findUser "Juliet Thunderwitch" with
| Some x -> print_endline "Juliet exists in database"
| None -> print_endline "Juliet not in database"

如果您不处理这两种情况,则代码甚至无法编译.所以类型系统保证你永远不会得到空引用异常,它保证你总是处理空值.如果一个函数返回user,它保证是一个对象的实际实例.太棒了.

If you don't handle both cases, the code won't even compile. So the type-system guarantees that you'll never get a null-reference exception, and it guarantees that you always handle nulls. And if a function returns user, its guaranteed to be an actual instance of an object. Awesomeness.

现在我们在 OP 的示例代码中看到了问题:

Now we see the problem in the OP's sample code:

class Class { ... }

void main() {
    Class c = new Class(); // set to new Class() by default
    // ... ... ... code ...
    for(int i = 0; i < c.count; ++i) { ... }
}

已初始化和未初始化的对象具有相同的数据类型,您无法区分它们之间的区别.有时,空对象模式 可能很有用,但上面的代码表明编译器没有办法以确定您是否正确使用了类型.

Initialized and uninitialized objects have the same datatype, you can't tell the difference between them. Occasionally, the null object pattern can be useful, but the code above demonstrates that the compiler has no way to determine whether you're using your types correctly.

这篇关于关于不可为空类型的争论的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆